home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume26 / tcx-1.1 / part01 next >
Encoding:
Text File  |  1993-04-04  |  88.3 KB  |  2,857 lines

  1. Newsgroups: comp.sources.unix
  2. From: slf@cs.mu.OZ.AU (Stewart Forster)
  3. Subject: v26i097: TCX v1.1 - Transparently Compressed Executables for UNIX, Part01/01
  4. Sender: unix-sources-moderator@vix.com
  5. Approved: paul@vix.com
  6.  
  7. Submitted-By: slf@cs.mu.OZ.AU (Stewart Forster)
  8. Posting-Number: Volume 26, Issue 97
  9. Archive-Name: tcx-1.1/part01
  10.  
  11. [ This version (1.1) of TCX is also available anonymous via FTP at
  12.     turiel.cs.mu.OZ.AU:pub/tcx1.1.tar.Z
  13. or    192.43.207.19:pub/tcx1.1.tar.Z
  14.   --vix ]
  15.  
  16. This release fixes many small bugs which prevented recompression of execs
  17. in certain circumstances.  It also adds a verified port to IBM's AIX, and
  18. an initial port to Linux which is not verified to be working (but probably
  19. does with fingers crossed).  Further support for the handling of symlinks
  20. to shell scripts was also tested and added.
  21.  
  22.     For those who don't know, TCX allows you to compress Unix executables
  23. using a compression algorithm of your choice (however GNU's gzip is highly
  24. recommended).  Once compressed, the executable may be run as normal.  The
  25. system provides transparent uncompression, (then execution), and finally
  26. recompression of the executable.  Recompression takes place after an installer
  27. defined interval of disuse, so one may balance the disk and cpu resources of
  28. the machine according to local needs, hence allowing for a smooth control of
  29. compressed disk space.  Features include emergency procedures in case of disk
  30. shortages when uncompressing, and a fairly robust scheme whereby files will not
  31. be lost if the system crashes during operations.  It also works for NFS mounted
  32. executables.
  33.  
  34.     Currently supported OS types are Ultrix, SunOS, Irix, AIX and Linux.
  35. Other OS support will come as nice people provide me with patches.  TCX is
  36. currently in use at the University of Melbourne, so it has continuing support.
  37.  
  38.             slf@cs.mu.OZ.AU (Stewart Forster)
  39.  
  40. #! /bin/sh
  41. # This is a shell archive.  Remove anything before this line, then unpack
  42. # it by saving it into a file and typing "sh file".  To overwrite existing
  43. # files, type "sh file -c".  You can also feed this as standard input via
  44. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  45. # will see the following message at the end:
  46. #        "End of archive 1 (of 1)."
  47. # Contents:  COPYING MANIFEST Makefile README VERSION config.h tcx.1
  48. #   tcx.c untcx.1 untcx.c
  49. # Wrapped by vixie@gw.home.vix.com on Mon Apr  5 03:06:07 1993
  50. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  51. if test -f 'COPYING' -a "${1}" != "-c" ; then 
  52.   echo shar: Will not clobber existing file \"'COPYING'\"
  53. else
  54. echo shar: Extracting \"'COPYING'\" \(17982 characters\)
  55. sed "s/^X//" >'COPYING' <<'END_OF_FILE'
  56. X            GNU GENERAL PUBLIC LICENSE
  57. X               Version 2, June 1991
  58. X
  59. X Copyright (C) 1989, 1991 Free Software Foundation, Inc.
  60. X                          675 Mass Ave, Cambridge, MA 02139, USA
  61. X Everyone is permitted to copy and distribute verbatim copies
  62. X of this license document, but changing it is not allowed.
  63. X
  64. X                Preamble
  65. X
  66. X  The licenses for most software are designed to take away your
  67. freedom to share and change it.  By contrast, the GNU General Public
  68. License is intended to guarantee your freedom to share and change free
  69. software--to make sure the software is free for all its users.  This
  70. General Public License applies to most of the Free Software
  71. XFoundation's software and to any other program whose authors commit to
  72. using it.  (Some other Free Software Foundation software is covered by
  73. the GNU Library General Public License instead.)  You can apply it to
  74. your programs, too.
  75. X
  76. X  When we speak of free software, we are referring to freedom, not
  77. price.  Our General Public Licenses are designed to make sure that you
  78. have the freedom to distribute copies of free software (and charge for
  79. this service if you wish), that you receive source code or can get it
  80. if you want it, that you can change the software or use pieces of it
  81. in new free programs; and that you know you can do these things.
  82. X
  83. X  To protect your rights, we need to make restrictions that forbid
  84. anyone to deny you these rights or to ask you to surrender the rights.
  85. These restrictions translate to certain responsibilities for you if you
  86. distribute copies of the software, or if you modify it.
  87. X
  88. X  For example, if you distribute copies of such a program, whether
  89. gratis or for a fee, you must give the recipients all the rights that
  90. you have.  You must make sure that they, too, receive or can get the
  91. source code.  And you must show them these terms so they know their
  92. rights.
  93. X
  94. X  We protect your rights with two steps: (1) copyright the software, and
  95. X(2) offer you this license which gives you legal permission to copy,
  96. distribute and/or modify the software.
  97. X
  98. X  Also, for each author's protection and ours, we want to make certain
  99. that everyone understands that there is no warranty for this free
  100. software.  If the software is modified by someone else and passed on, we
  101. want its recipients to know that what they have is not the original, so
  102. that any problems introduced by others will not reflect on the original
  103. authors' reputations.
  104. X
  105. X  Finally, any free program is threatened constantly by software
  106. patents.  We wish to avoid the danger that redistributors of a free
  107. program will individually obtain patent licenses, in effect making the
  108. program proprietary.  To prevent this, we have made it clear that any
  109. patent must be licensed for everyone's free use or not licensed at all.
  110. X
  111. X  The precise terms and conditions for copying, distribution and
  112. modification follow.
  113. X
  114. X            GNU GENERAL PUBLIC LICENSE
  115. X   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
  116. X
  117. X  0. This License applies to any program or other work which contains
  118. a notice placed by the copyright holder saying it may be distributed
  119. under the terms of this General Public License.  The "Program", below,
  120. refers to any such program or work, and a "work based on the Program"
  121. means either the Program or any derivative work under copyright law:
  122. that is to say, a work containing the Program or a portion of it,
  123. either verbatim or with modifications and/or translated into another
  124. language.  (Hereinafter, translation is included without limitation in
  125. the term "modification".)  Each licensee is addressed as "you".
  126. X
  127. Activities other than copying, distribution and modification are not
  128. covered by this License; they are outside its scope.  The act of
  129. running the Program is not restricted, and the output from the Program
  130. is covered only if its contents constitute a work based on the
  131. Program (independent of having been made by running the Program).
  132. Whether that is true depends on what the Program does.
  133. X
  134. X  1. You may copy and distribute verbatim copies of the Program's
  135. source code as you receive it, in any medium, provided that you
  136. conspicuously and appropriately publish on each copy an appropriate
  137. copyright notice and disclaimer of warranty; keep intact all the
  138. notices that refer to this License and to the absence of any warranty;
  139. and give any other recipients of the Program a copy of this License
  140. along with the Program.
  141. X
  142. You may charge a fee for the physical act of transferring a copy, and
  143. you may at your option offer warranty protection in exchange for a fee.
  144. X
  145. X  2. You may modify your copy or copies of the Program or any portion
  146. of it, thus forming a work based on the Program, and copy and
  147. distribute such modifications or work under the terms of Section 1
  148. above, provided that you also meet all of these conditions:
  149. X
  150. X    a) You must cause the modified files to carry prominent notices
  151. X    stating that you changed the files and the date of any change.
  152. X
  153. X    b) You must cause any work that you distribute or publish, that in
  154. X    whole or in part contains or is derived from the Program or any
  155. X    part thereof, to be licensed as a whole at no charge to all third
  156. X    parties under the terms of this License.
  157. X
  158. X    c) If the modified program normally reads commands interactively
  159. X    when run, you must cause it, when started running for such
  160. X    interactive use in the most ordinary way, to print or display an
  161. X    announcement including an appropriate copyright notice and a
  162. X    notice that there is no warranty (or else, saying that you provide
  163. X    a warranty) and that users may redistribute the program under
  164. X    these conditions, and telling the user how to view a copy of this
  165. X    License.  (Exception: if the Program itself is interactive but
  166. X    does not normally print such an announcement, your work based on
  167. X    the Program is not required to print an announcement.)
  168. X
  169. These requirements apply to the modified work as a whole.  If
  170. identifiable sections of that work are not derived from the Program,
  171. and can be reasonably considered independent and separate works in
  172. themselves, then this License, and its terms, do not apply to those
  173. sections when you distribute them as separate works.  But when you
  174. distribute the same sections as part of a whole which is a work based
  175. on the Program, the distribution of the whole must be on the terms of
  176. this License, whose permissions for other licensees extend to the
  177. entire whole, and thus to each and every part regardless of who wrote it.
  178. X
  179. Thus, it is not the intent of this section to claim rights or contest
  180. your rights to work written entirely by you; rather, the intent is to
  181. exercise the right to control the distribution of derivative or
  182. collective works based on the Program.
  183. X
  184. In addition, mere aggregation of another work not based on the Program
  185. with the Program (or with a work based on the Program) on a volume of
  186. a storage or distribution medium does not bring the other work under
  187. the scope of this License.
  188. X
  189. X  3. You may copy and distribute the Program (or a work based on it,
  190. under Section 2) in object code or executable form under the terms of
  191. Sections 1 and 2 above provided that you also do one of the following:
  192. X
  193. X    a) Accompany it with the complete corresponding machine-readable
  194. X    source code, which must be distributed under the terms of Sections
  195. X    1 and 2 above on a medium customarily used for software interchange; or,
  196. X
  197. X    b) Accompany it with a written offer, valid for at least three
  198. X    years, to give any third party, for a charge no more than your
  199. X    cost of physically performing source distribution, a complete
  200. X    machine-readable copy of the corresponding source code, to be
  201. X    distributed under the terms of Sections 1 and 2 above on a medium
  202. X    customarily used for software interchange; or,
  203. X
  204. X    c) Accompany it with the information you received as to the offer
  205. X    to distribute corresponding source code.  (This alternative is
  206. X    allowed only for noncommercial distribution and only if you
  207. X    received the program in object code or executable form with such
  208. X    an offer, in accord with Subsection b above.)
  209. X
  210. The source code for a work means the preferred form of the work for
  211. making modifications to it.  For an executable work, complete source
  212. code means all the source code for all modules it contains, plus any
  213. associated interface definition files, plus the scripts used to
  214. control compilation and installation of the executable.  However, as a
  215. special exception, the source code distributed need not include
  216. anything that is normally distributed (in either source or binary
  217. form) with the major components (compiler, kernel, and so on) of the
  218. operating system on which the executable runs, unless that component
  219. itself accompanies the executable.
  220. X
  221. If distribution of executable or object code is made by offering
  222. access to copy from a designated place, then offering equivalent
  223. access to copy the source code from the same place counts as
  224. distribution of the source code, even though third parties are not
  225. compelled to copy the source along with the object code.
  226. X
  227. X  4. You may not copy, modify, sublicense, or distribute the Program
  228. except as expressly provided under this License.  Any attempt
  229. otherwise to copy, modify, sublicense or distribute the Program is
  230. void, and will automatically terminate your rights under this License.
  231. However, parties who have received copies, or rights, from you under
  232. this License will not have their licenses terminated so long as such
  233. parties remain in full compliance.
  234. X
  235. X  5. You are not required to accept this License, since you have not
  236. signed it.  However, nothing else grants you permission to modify or
  237. distribute the Program or its derivative works.  These actions are
  238. prohibited by law if you do not accept this License.  Therefore, by
  239. modifying or distributing the Program (or any work based on the
  240. Program), you indicate your acceptance of this License to do so, and
  241. all its terms and conditions for copying, distributing or modifying
  242. the Program or works based on it.
  243. X
  244. X  6. Each time you redistribute the Program (or any work based on the
  245. Program), the recipient automatically receives a license from the
  246. original licensor to copy, distribute or modify the Program subject to
  247. these terms and conditions.  You may not impose any further
  248. restrictions on the recipients' exercise of the rights granted herein.
  249. You are not responsible for enforcing compliance by third parties to
  250. this License.
  251. X
  252. X  7. If, as a consequence of a court judgment or allegation of patent
  253. infringement or for any other reason (not limited to patent issues),
  254. conditions are imposed on you (whether by court order, agreement or
  255. otherwise) that contradict the conditions of this License, they do not
  256. excuse you from the conditions of this License.  If you cannot
  257. distribute so as to satisfy simultaneously your obligations under this
  258. License and any other pertinent obligations, then as a consequence you
  259. may not distribute the Program at all.  For example, if a patent
  260. license would not permit royalty-free redistribution of the Program by
  261. all those who receive copies directly or indirectly through you, then
  262. the only way you could satisfy both it and this License would be to
  263. refrain entirely from distribution of the Program.
  264. X
  265. If any portion of this section is held invalid or unenforceable under
  266. any particular circumstance, the balance of the section is intended to
  267. apply and the section as a whole is intended to apply in other
  268. circumstances.
  269. X
  270. It is not the purpose of this section to induce you to infringe any
  271. patents or other property right claims or to contest validity of any
  272. such claims; this section has the sole purpose of protecting the
  273. integrity of the free software distribution system, which is
  274. implemented by public license practices.  Many people have made
  275. generous contributions to the wide range of software distributed
  276. through that system in reliance on consistent application of that
  277. system; it is up to the author/donor to decide if he or she is willing
  278. to distribute software through any other system and a licensee cannot
  279. impose that choice.
  280. X
  281. This section is intended to make thoroughly clear what is believed to
  282. be a consequence of the rest of this License.
  283. X
  284. X  8. If the distribution and/or use of the Program is restricted in
  285. certain countries either by patents or by copyrighted interfaces, the
  286. original copyright holder who places the Program under this License
  287. may add an explicit geographical distribution limitation excluding
  288. those countries, so that distribution is permitted only in or among
  289. countries not thus excluded.  In such case, this License incorporates
  290. the limitation as if written in the body of this License.
  291. X
  292. X  9. The Free Software Foundation may publish revised and/or new versions
  293. of the General Public License from time to time.  Such new versions will
  294. be similar in spirit to the present version, but may differ in detail to
  295. address new problems or concerns.
  296. X
  297. XEach version is given a distinguishing version number.  If the Program
  298. specifies a version number of this License which applies to it and "any
  299. later version", you have the option of following the terms and conditions
  300. either of that version or of any later version published by the Free
  301. Software Foundation.  If the Program does not specify a version number of
  302. this License, you may choose any version ever published by the Free Software
  303. XFoundation.
  304. X
  305. X  10. If you wish to incorporate parts of the Program into other free
  306. programs whose distribution conditions are different, write to the author
  307. to ask for permission.  For software which is copyrighted by the Free
  308. Software Foundation, write to the Free Software Foundation; we sometimes
  309. make exceptions for this.  Our decision will be guided by the two goals
  310. of preserving the free status of all derivatives of our free software and
  311. of promoting the sharing and reuse of software generally.
  312. X
  313. X                NO WARRANTY
  314. X
  315. X  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
  316. XFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
  317. OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
  318. PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
  319. OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  320. MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
  321. TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
  322. PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
  323. REPAIR OR CORRECTION.
  324. X
  325. X  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
  326. WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
  327. REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
  328. INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
  329. OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
  330. TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
  331. YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
  332. PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
  333. POSSIBILITY OF SUCH DAMAGES.
  334. X
  335. X             END OF TERMS AND CONDITIONS
  336. X
  337. X    Appendix: How to Apply These Terms to Your New Programs
  338. X
  339. X  If you develop a new program, and you want it to be of the greatest
  340. possible use to the public, the best way to achieve this is to make it
  341. free software which everyone can redistribute and change under these terms.
  342. X
  343. X  To do so, attach the following notices to the program.  It is safest
  344. to attach them to the start of each source file to most effectively
  345. convey the exclusion of warranty; and each file should have at least
  346. the "copyright" line and a pointer to where the full notice is found.
  347. X
  348. X    <one line to give the program's name and a brief idea of what it does.>
  349. X    Copyright (C) 19yy  <name of author>
  350. X
  351. X    This program is free software; you can redistribute it and/or modify
  352. X    it under the terms of the GNU General Public License as published by
  353. X    the Free Software Foundation; either version 2 of the License, or
  354. X    (at your option) any later version.
  355. X
  356. X    This program is distributed in the hope that it will be useful,
  357. X    but WITHOUT ANY WARRANTY; without even the implied warranty of
  358. X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  359. X    GNU General Public License for more details.
  360. X
  361. X    You should have received a copy of the GNU General Public License
  362. X    along with this program; if not, write to the Free Software
  363. X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  364. X
  365. Also add information on how to contact you by electronic and paper mail.
  366. X
  367. If the program is interactive, make it output a short notice like this
  368. when it starts in an interactive mode:
  369. X
  370. X    Gnomovision version 69, Copyright (C) 19yy name of author
  371. X    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
  372. X    This is free software, and you are welcome to redistribute it
  373. X    under certain conditions; type `show c' for details.
  374. X
  375. The hypothetical commands `show w' and `show c' should show the appropriate
  376. parts of the General Public License.  Of course, the commands you use may
  377. be called something other than `show w' and `show c'; they could even be
  378. mouse-clicks or menu items--whatever suits your program.
  379. X
  380. You should also get your employer (if you work as a programmer) or your
  381. school, if any, to sign a "copyright disclaimer" for the program, if
  382. necessary.  Here is a sample; alter the names:
  383. X
  384. X  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  385. X  `Gnomovision' (which makes passes at compilers) written by James Hacker.
  386. X
  387. X  <signature of Ty Coon>, 1 April 1989
  388. X  Ty Coon, President of Vice
  389. X
  390. This General Public License does not permit incorporating your program into
  391. proprietary programs.  If your program is a subroutine library, you may
  392. consider it more useful to permit linking proprietary applications with the
  393. library.  If this is what you want to do, use the GNU Library General
  394. Public License instead of this License.
  395. END_OF_FILE
  396. if test 17982 -ne `wc -c <'COPYING'`; then
  397.     echo shar: \"'COPYING'\" unpacked with wrong size!
  398. fi
  399. # end of 'COPYING'
  400. fi
  401. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  402.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  403. else
  404. echo shar: Extracting \"'MANIFEST'\" \(424 characters\)
  405. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  406. X   File Name        Archive #    Description
  407. X-----------------------------------------------------------
  408. X COPYING                    1    
  409. X MANIFEST                   1    This shipping list
  410. X Makefile                   1    
  411. X README                     1    
  412. X VERSION                    1    
  413. X config.h                   1    
  414. X tcx.1                      1    
  415. X tcx.c                      1    
  416. X untcx.1                    1    
  417. X untcx.c                    1    
  418. END_OF_FILE
  419. if test 424 -ne `wc -c <'MANIFEST'`; then
  420.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  421. fi
  422. # end of 'MANIFEST'
  423. fi
  424. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  425.   echo shar: Will not clobber existing file \"'Makefile'\"
  426. else
  427. echo shar: Extracting \"'Makefile'\" \(642 characters\)
  428. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  429. X#
  430. X#        Makefile for tcx
  431. X#
  432. X#    Author : Stewart Forster, University Of Melbourne, 25/31993
  433. X#
  434. X
  435. X# C compiler of your choice.  Should be ansi'ish
  436. CC = cc            # IRIX, ULTRIX, AIX
  437. X#CC = gcc        # SUNOS
  438. X
  439. X
  440. X# Cflags of choice.
  441. CFLAGS = -s -O        # Most OS's
  442. X#CFLAGS = -s -O6 -fomit-frame-pointer -Wall    # Linux
  443. X
  444. X
  445. X# Any libraries
  446. LIBS = -lmalloc -lc_s    # IRIX
  447. X#LIBS =            # SUNOS, ULTRIX, AIX
  448. X
  449. X
  450. all:    tcx untcx
  451. X
  452. tcx:    tcx.c config.h
  453. X    $(CC) $(CFLAGS) -o tcx tcx.c $(LIBS)
  454. X
  455. untcx:    untcx.c config.h
  456. X    $(CC) $(CFLAGS) -o untcx untcx.c $(LIBS)
  457. X
  458. shar:
  459. X    shar -c -l 45 -o tcx README VERSION COPYING Makefile tcx.1 untcx.1 tcx.c config.h untcx.c
  460. X
  461. clean:
  462. X    /bin/rm -f *.o tcx untcx
  463. END_OF_FILE
  464. if test 642 -ne `wc -c <'Makefile'`; then
  465.     echo shar: \"'Makefile'\" unpacked with wrong size!
  466. fi
  467. # end of 'Makefile'
  468. fi
  469. if test -f 'README' -a "${1}" != "-c" ; then 
  470.   echo shar: Will not clobber existing file \"'README'\"
  471. else
  472. echo shar: Extracting \"'README'\" \(5296 characters\)
  473. sed "s/^X//" >'README' <<'END_OF_FILE'
  474. X    TCX - Transparently Compressed Executables (For Unix)
  475. X
  476. X                by
  477. X
  478. X       Stewart Forster, University Of Melbourne, 1993
  479. X
  480. TCX is a system designed for the transparent decompression, execution
  481. and recompression of executables under Unix.  It allows configuration
  482. options such as the type of compression system used (compress(1),
  483. gzip(1), your own local system etc), timeouts between recompressions,
  484. and emergency directories in case a decompression fails from shortage
  485. of disk space.  The system is designed with a reasonable amount of
  486. robustness in mind, such as in the event of system crashes, or races
  487. on trying to uncompress, compress or execute something.
  488. X
  489. X    Currently TCX is only proven to run on Irix 4.*, Ultrix 4.2
  490. or higher, and SunOs 4.1.1 or higher.  It may run on other releases
  491. of these OS's but has not been tested.  It should also be relatively
  492. easy to port to other OS's as much of the code is fairly straight
  493. forward.
  494. X
  495. X    The system is used here at the Department of Computer Science
  496. University Of Melbourne, and in other departments on campus.  This is
  497. the first official release of TCX to the world, so please feel free
  498. to comment or help in bug fixes and machine reports by sending email
  499. to slf@cs.mu.OZ.AU
  500. X
  501. X---------------------------------------------------------------------
  502. X
  503. X            INSTALLATION
  504. X
  505. TCX is a small package with just the following files. If you don't
  506. have these three file, get a complete distribution.
  507. X
  508. X        config.h
  509. X        tcx.c
  510. X        untcx.c
  511. X
  512. XFirst read the "FURTHER INFO" section below before configuring TCX
  513. for your system, since it may influence some of your decisions.
  514. X
  515. To configure TCX, edit the config.h file.  There are enough directions
  516. therein to help you configure for your system.  TCX relies on the
  517. compression system you use to barf when the filesystem gets full
  518. and return a fail exit code.  If the compression system you use
  519. doesn't do this, you run the risk of losing files. The GNU gzip
  520. package is known to do the correct safety checks and exit accordingly.
  521. X
  522. Once done editing the config file, edit the Makefile to set the C
  523. compiler and libraries for your system, and compile.
  524. Don't worry if your optimizer complains of no exit points in the
  525. procedures called "check_tcxd_mode", "untcx_and_exec_local", and
  526. X"untcx_and_exec_nfs" when compiling untcx.c, these are normal.
  527. X
  528. The tcx, and untcx executables must be placed at the pathnames you
  529. specified for them in config.h, if they are not there, the system
  530. will NOT work. eg.
  531. X
  532. X    cp tcx /usr/local/bin/tcx
  533. X    cp untcx /usr/local/bin/untcx
  534. X
  535. Untcx must also be installed setuid, so issue the following command.
  536. X
  537. X    chown root /usr/local/bin/untcx
  538. X    chmod 4711 /usr/local/bin/untcx     (or path you chose)
  539. X
  540. Do not install the "tcx" executable setuid to anyone.
  541. X
  542. and copy the manual pages to your regular man directory and read them.
  543. X
  544. X    The installation is now complete.
  545. X
  546. X----------------------------------------------------------------------
  547. X
  548. X        TESTING YOUR INSTALLATION
  549. X
  550. You can now try running "tcx" on an innocuous executable to transform
  551. it, and then try running it.  Wait for the timeout interval you
  552. specified (after disuse, which means not even reading the file) and it
  553. should recompress.  If it doesn't recompress after about twice the
  554. interval specified, check the following.
  555. X
  556. X1) Access times on the file. MAKE SURE it wasn't touched before suspecting
  557. X   something is wrong.
  558. X2) That the daemon mode for untcx started correctly.  The pid should be
  559. X   stored in ENFSDIR/.lock.  Assuming ENFSDIR is /tmp/exec as in the
  560. X   distributed config file, issue
  561. X
  562. X    ps `cat /tmp/exec/.lock`   and check that the daemon started.
  563. X
  564. X   If it didn't, there is a minor problem with permissions, or maybe
  565. X   you specified a read-only file system for ENFSDIR.
  566. X3) Check if you installed tcx where PATHTCX in the config file said
  567. X   where it was.
  568. X4) Check that the uncompressor is where PATHUNPACK in the the config
  569. X   file says it is.
  570. X
  571. If all else comes to nought, look into the source code, or mail your
  572. system configuration and config file to slf@cs.mu.OZ.AU, and I'll
  573. try and see what can be done.
  574. X
  575. X----------------------------------------------------------------------
  576. X
  577. X    FUTHER INFO / POTENTIAL BUGS
  578. X
  579. Users may experience a slight delay when a TCX executable is started up
  580. due the decompression phase.  If this becomes a problem for large
  581. executables, you should probably discourage use of TCX on these huge
  582. binaries.  The "gzip" system decompresses at around 500-700K/sec on the
  583. systems I tested it on, which are all around the 25 SPECmark rating.
  584. X
  585. Don't use TCX on NFS mounted shell scripts which rely on `dirname $0`
  586. because TCX cannot fool the shell into giving it a spoof $0, like it
  587. can with binaries.  This may be the only case (other than setuid
  588. programs) where TCX will break something.
  589. X
  590. X----------------------------------------------------------------------
  591. X
  592. X        THANKS
  593. X
  594. Special thanks go to Robert Elz, who provided invaluable input,
  595. suggestions and clarifications on the whole idea.
  596. X
  597. Thanks also to Jeff Shultz who provided some potential "sticky" cases
  598. which gave me some more work to do (plus made tcx more robust).
  599. X
  600. Many thanks go the the overwhelming input provided by many people
  601. around the world, all interested in seeing TCX working correctly on
  602. their system.  Your input is what makes good software better.
  603. X
  604. X                Stewart.
  605. X
  606. END_OF_FILE
  607. if test 5296 -ne `wc -c <'README'`; then
  608.     echo shar: \"'README'\" unpacked with wrong size!
  609. fi
  610. # end of 'README'
  611. fi
  612. if test -f 'VERSION' -a "${1}" != "-c" ; then 
  613.   echo shar: Will not clobber existing file \"'VERSION'\"
  614. else
  615. echo shar: Extracting \"'VERSION'\" \(4546 characters\)
  616. sed "s/^X//" >'VERSION' <<'END_OF_FILE'
  617. Version 1.1    (5/4/1993)    Stewart Forster
  618. X    untcx.c        v1.0.5
  619. X        - Fixed statfs code which had the wrong call args for
  620. X        SunOs and Ultrix (but didn't make any diff though).
  621. X        Thanks to H.J.Lu for pointing that one out
  622. X        - Completed AIX port
  623. X        - Added LINUX patches, these may be somewhat confused as
  624. X        the person who provided the patches did not understand
  625. X        the way untcx invokes itself, so they were re-patched by
  626. X        me without a machine to test them on.
  627. X        Thanks to H.J.Lu for the patches.
  628. X        - Fixed timeout code which was resetting inode mod times
  629. X        which I was later using to see if file had changed.
  630. X        This would only prevent execs from recompressing if they
  631. X        had been running for longer than the LOCALTIMEOUT period.
  632. X        - Fixed checks on symlinks over NFS.
  633. X        - Fixed bug whereby if an exec was run, in between the
  634. X        latent stage after recompression and before untcx noted
  635. X        that the recompression had completed, it would not get
  636. X        recompressed.
  637. X    config.h    v1.0.3
  638. X        - Removed the need for utime() dependent includes.
  639. X        - Added AIX #defs
  640. Version 1.0.4    (1/4/1993)    Stewart Forster
  641. X    untcx.c        v1.0.4
  642. X        - Added symlink code to handle cases where a symlink to
  643. X        a shell script resulted in the shell script being called
  644. X        with $0 was being set to the path of the script, and not
  645. X        the symlink.  Added stuff so untcx would create symlinks
  646. X        in ENFSDIR as well, and manage them (including floating
  647. X        links) properly. (I hope!)  Resulting fix results in
  648. X        `basename $0` equalling the basename of the symlink,
  649. X        although `dirname $0` will be different (unavoidable).
  650. X        This problem should affect almost nobody, unless a shell
  651. X        script gets picky about `dirname $0`, in which case you
  652. X        should not tcx such scripts. :-(
  653. X        - Changed the execl for the "unpacker" to pass along the
  654. X        pathname of the uncompressor through argv[0], rather than
  655. X        "unpacker", which was what was confusing the Unix compress
  656. X        system (silly me!)
  657. X        Thanks to Lionel Mallet for pointing this out.
  658. X    tcx.c        v1.0.4
  659. X        - Changed the execl for the "packer" to pass along the
  660. X        pathname of the compressor through argv[0], rather than
  661. X        "packer", which was what was confusing the Unix compress
  662. X        system (silly me!)
  663. X        Thanks to Lionel Mallet for pointing this out.
  664. Version 1.0.3    (30/3/1993)    Stewart Forster
  665. X    untcx.c        v1.0.3
  666. X        - Fixed a race condition bug whereby under SUNOS, if
  667. X        untcx encountered a local executable, that had just been
  668. X        unpacked while it was setting up, it would get stuck in
  669. X        an infinite loop.  This race is pretty slim, but may have
  670. X        happened on large multi-user systems.
  671. X        - Fixed symlink resolving bug.  Didn't check for length
  672. X        returned from readlink, and was strcat-ing strings that
  673. X        were not always null-terminated!
  674. X        - Added #ifdef to allow tcx to ALWAYS unpack to /tmp.
  675. X        Suggestion by Mike Lawley.
  676. X        - Added code to unpack to ENFSDIR if file being unpacked
  677. X        has a link count greater than 1, so that hard links may
  678. X        be preserved.
  679. X    tcx.c        v1.0.3
  680. X        - Added symbolic link resolving code from untcx.c, to
  681. X        allow tcx to operate on symlinks.  Added symlink bug fix.
  682. X        Suggestion by Richard van de Stadt.
  683. X        - Added code to check for hard link count, and abort with
  684. X        a warning if count is greater than 1.  This prevents the
  685. X        destruction of hard links when packing.
  686. X    config.h    v1.0.2
  687. X        - Added UNPACK_IN_PLACE option definition.
  688. X
  689. Version 1.0.2    (27/3/1993)    Stewart Forster
  690. X    untcx.c        v1.0.2
  691. X        - Added open file table reference count to internal hash
  692. X        tables for SUNOS.  This means that inodes won't have to
  693. X        time out before recompressing the file they point to.
  694. X          Thanks to Mike Lawley for pointing out problem
  695. X        - Fixed tragic bug in pathname resolution that would have
  696. X        caused a lot of problems when a program needs to access
  697. X        files in the directory in which it was invoked, and not
  698. X        where it lived! Also the cause of incorrect pathname
  699. X        generation on NFS mounted executables placed in ENFSDIR.
  700. X        Thanks to many who directly and indirectly reported this.
  701. X
  702. Version 1.0.1    (26/3/1993)    Stewart Forster
  703. X    tcx.c        v1.0.2
  704. X        - Worked around Ultrix file lock problem on NFS mounted
  705. X        files.  Ultrix 4.2 can't lock NFS files.
  706. X            v1.0.1
  707. X        - Rewrote scratch file creation code to fix Ultrix
  708. X        ftruncate bug reported by John Adcock and Joel Fine.
  709. X        Removed the need for ftruncate().
  710. X    untcx.c        v1.0.1
  711. X        - Fixed trailing slash on mkdir argument which Ultrix
  712. X        barfs on. Reported by John Adcock.
  713. X    config.h    v1.0.1
  714. X        - Added comments about not using tmpfs on SUNOS for ENFSDIR
  715. X
  716. Version 1.0    (25/3/1993)    (Original Release)    Stewart Forster
  717. X    tcx.c        v1.0
  718. X    untcx.c        v1.0        
  719. X    config.h    v1.0
  720. END_OF_FILE
  721. if test 4546 -ne `wc -c <'VERSION'`; then
  722.     echo shar: \"'VERSION'\" unpacked with wrong size!
  723. fi
  724. # end of 'VERSION'
  725. fi
  726. if test -f 'config.h' -a "${1}" != "-c" ; then 
  727.   echo shar: Will not clobber existing file \"'config.h'\"
  728. else
  729. echo shar: Extracting \"'config.h'\" \(8049 characters\)
  730. sed "s/^X//" >'config.h' <<'END_OF_FILE'
  731. X/* config.h, Version 1.0.3, 5/4/1993 by Stewart Forster */
  732. X
  733. X/************************************************************************/
  734. X/*   Copyright (C) 1993 Stewart Forster                    */
  735. X/*  This program is free software; you can redistribute it and/or modify*/
  736. X/*  it under the terms of the GNU General Public License as published by*/
  737. X/*  the Free Software Foundation; either version 2, or (at your option) */
  738. X/*  any later version.                            */
  739. X/*                                    */
  740. X/*  This program is distributed in the hope that it will be useful,    */
  741. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of    */
  742. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    */
  743. X/*  GNU General Public License for more details.            */
  744. X/*                                    */
  745. X/*  You should have received a copy of the GNU General Public License    */
  746. X/*  along with this program; if not, write to the Free Software        */
  747. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.        */
  748. X/************************************************************************/
  749. X
  750. X
  751. X/************************************************************************/
  752. X/*    OS TYPE DEFINITION                        */
  753. X/* Define one of the following where appropriate            */
  754. X/************************************************************************/
  755. X
  756. X/* #define    SUNOS        /* */
  757. X#define    IRIX        /* */
  758. X/* #define    AIX        /* */
  759. X/* #define    ULTRIX        /* */
  760. X/* #define    LINUX        /* */
  761. X
  762. X/************************************************************************/
  763. X/* SUNOS requires the pstat command to be available.  This is part of     */
  764. X/* the SunOs distribution but fix this following path if it's wrong.    */
  765. X/************************************************************************/
  766. X
  767. X#ifdef SUNOS
  768. X#define    PSTATI    "/usr/etc/pstat -i"
  769. X#endif
  770. X
  771. X/************************************************************************/
  772. X/* PATHUNTCX is the pathname where the untcx executable resides.  Note    */
  773. X/* that this is the interpreter/unpacker and hence must exist with this    */
  774. X/* path, or else the whole system will fail! This path should also be on*/
  775. X/* a filesystem which the local system trusts setuid binaries from,    */
  776. X/* since PATHUNTCX must run setuid to root.                */
  777. X/************************************************************************/
  778. X
  779. X#define    PATHUNTCX    "/usr/local/bin/untcx"
  780. X
  781. X/************************************************************************/
  782. X/* PATHTCX is the pathname to the tcx executable.  This should NOT be    */
  783. X/* installed setuid root.                        */
  784. X/************************************************************************/
  785. X
  786. X#define    PATHTCX        "/usr/local/bin/tcx"
  787. X
  788. X/************************************************************************/
  789. X/* PATHPACKER is the pathname to the compression program you wish to use*/
  790. X/* with the system. PACKEROPTS is an optional definition of options you    */
  791. X/* wish to pass to the packer program. NB. The compression program must    */
  792. X/* be a `filter', that is, it is capable of reading from stdion and    */
  793. X/* compressing to stdout.                        */
  794. X/************************************************************************/
  795. X
  796. X#define    PATHPACKER    "/usr/local/bin/gzip"
  797. X/*#define    PACKEROPTS    "-7"            /* Optional */
  798. X
  799. X/************************************************************************/
  800. X/* PATHUNPACK and the optional UNPACKOPTS serve a similar purpose to    */
  801. X/* PATHPACKER and PACKEROPTS above.                    */
  802. X/************************************************************************/
  803. X
  804. X#define    PATHUNPACK    "/usr/local/bin/gzip"
  805. X#define    UNPACKOPTS    "-d"            /* Optional */
  806. X
  807. X/************************************************************************/
  808. X/* UNPACK_IN_PLACE instructs the uncrompressor to unpack an executable    */
  809. X/* where it lives if it resides on the local machine.  This is useful    */
  810. X/* on machines with small /tmp's, plus it evenly distributes the disk    */
  811. X/* workload.  It is generally deemed useful to have it turned on.    */
  812. X/* Comment this out if you have a large unpack area for ENFSDIR (below)    */
  813. X/* or if you have very limited CPU resources, since unpacking in place    */
  814. X/* means that untcx will have to recompress the file later, rather than    */
  815. X/* just deleting the temporary one from ENFSDIR.            */
  816. X/************************************************************************/
  817. X
  818. X#define    UNPACK_IN_PLACE    /* */
  819. X
  820. X/************************************************************************/
  821. X/* ENFSDIR is the pathname to the directory where emergency (out of disk*/
  822. X/* space locally) or NFS mounted executables get unpacked to.        */
  823. X/* On SUNOS, if you are using the "tmpfs", you will have to set ENFSDIR    */
  824. X/* to a "real disk". (A "real disk" may also be an NFS mounted partition*/
  825. X/* to which the machine has root access to).  There seems to be some    */
  826. X/* problem with fcntl locks on SUNOS tmpfs.                */
  827. X/************************************************************************/
  828. X
  829. X#define    ENFSDIR        "/tmp/exec"
  830. X
  831. X/************************************************************************/
  832. X/* SCANRATE is the interval in seconds which the tcx daemon waits before*/
  833. X/* rescanning all files it is currently managing, for recompression in    */
  834. X/* the case of local files, or deletion from ENFSDIR in the case of     */
  835. X/* emergency or NFS mounted executables.  Note that SCANRATE should    */
  836. X/* probably not be larger than ENFSTIMEOUT or LOCALTIMEOUT defined    */
  837. X/* below, otherwise you will undermine the purpose of those variables.    */
  838. X/************************************************************************/
  839. X
  840. X#define    SCANRATE    60        /* 60 seconds between scans */
  841. X
  842. X/************************************************************************/
  843. X/* ENFSTIMEOUT is the least number of seconds of disuse of an executable*/
  844. X/* residing in ENFSDIR the tcx daemon will wait for, before it attempts    */
  845. X/* to delete the executable. This should be set quite low if there isn't*/
  846. X/* much disk space available in ENFSDIR.                */
  847. X/* On SUNOS, this value only sets in after the inode is timed out of the*/
  848. X/* inode cache.  This problem will be addressed in a future release.    */
  849. X/************************************************************************/
  850. X
  851. X#define    ENFSTIMEOUT    300        /* 5 minutes of inactivity */
  852. X
  853. X/************************************************************************/
  854. X/* LOCALTIMEOUT is the least number of seconds of disuse of an        */
  855. X/* executable residing locally on the system that the tcx will wait    */
  856. X/* before attempting to repack the executable.                */
  857. X/* On SUNOS, this value only sets in after the inode is timed out of the*/
  858. X/* inode cache.  This problem will be addressed in a future release.    */
  859. X/************************************************************************/
  860. X
  861. X#define    LOCALTIMEOUT    3600        /* 1 hour of inactivity */
  862. X
  863. X
  864. X/************************************************************************/
  865. X/************************************************************************/
  866. X/* You should not need to edit anything after this point        */
  867. X/************************************************************************/
  868. X/************************************************************************/
  869. X
  870. X#define    MAXHEADERSIZE    256
  871. X#define    SIGTYPE    int
  872. X
  873. X/* Define PUSLEEP (portable usleep definition)    */
  874. X
  875. X#if defined(LINUX)
  876. X#define    __USE_BSD_SIGNAL
  877. X#define    SIGTYPE    void
  878. X#endif
  879. X
  880. X#if defined(IRIX)
  881. X#define _BSD_SIGNALS
  882. X#define    PUSLEEP(x)    (sginap((long)((x)/10000)))
  883. X#endif
  884. X
  885. X#if defined(ULTRIX) || defined(SUNOS) || defined(AIX) || defined(LINUX)
  886. X#define    PUSLEEP(x)    (usleep(x))    /* usleep code in untcx.c for ULTRIX */
  887. X#endif
  888. X
  889. X#ifdef __STDC__
  890. X#include    <stdlib.h>
  891. X#endif
  892. X#include        <unistd.h>
  893. X#include        <sys/time.h>
  894. X#include        <sys/wait.h>
  895. X
  896. X#if defined(AIX)
  897. X#include    <sys/id.h>
  898. X#endif
  899. X
  900. X#include        <sys/types.h>
  901. X
  902. X#if defined(ULTRIX) || defined(LINUX)
  903. X#include    <sys/param.h>
  904. X#include    <sys/mount.h>
  905. X#endif
  906. X
  907. X#if defined(IRIX) || defined(AIX)
  908. X#include        <sys/statfs.h>
  909. X#endif
  910. X
  911. X#if defined(SUNOS) || defined(LINUX)
  912. X#include        <sys/vfs.h>
  913. X#endif
  914. X
  915. X#include        <sys/stat.h>
  916. X#include    <fcntl.h>
  917. X#include        <string.h>
  918. X#include        <errno.h>
  919. X#include        <signal.h>
  920. X#include        <stdio.h>
  921. X
  922. X#ifndef    MAXPATHLEN
  923. X#define    MAXPATHLEN    1024
  924. X#endif
  925. END_OF_FILE
  926. if test 8049 -ne `wc -c <'config.h'`; then
  927.     echo shar: \"'config.h'\" unpacked with wrong size!
  928. fi
  929. # end of 'config.h'
  930. fi
  931. if test -f 'tcx.1' -a "${1}" != "-c" ; then 
  932.   echo shar: Will not clobber existing file \"'tcx.1'\"
  933. else
  934. echo shar: Extracting \"'tcx.1'\" \(2208 characters\)
  935. sed "s/^X//" >'tcx.1' <<'END_OF_FILE'
  936. X.TH TCX 1 "19 March 1993"
  937. X.UC Melb
  938. X.SH NAME
  939. tcx \- Transparantly compress executables
  940. X.SH SYNOPSIS
  941. tcx filename
  942. X.SH DESCRIPTION
  943. X.B Tcx
  944. will replace an executable with a compressed version of it that is still
  945. capable of being executed.  The amount of savings will depend on the
  946. compression algorithm configured for use by tcx.
  947. An executable compressed with tcx can be run as per normal with (hopefully) no
  948. side effects other than a minor delay in startup time.
  949. X.PP
  950. XExecutables local to the system (not NFS mounted) are uncompressed in place
  951. and recompressed again some time after it stops being used.  The standard
  952. timeout is 1/2 an hour.
  953. X.PP
  954. XExecutables residing on NFS mounted directores are unpacked to a directory local
  955. to the system and run from there.  These executables lie around for about one
  956. minute after disuse, after which time they get deleted.
  957. X.PP
  958. All this action is transparant to the user, but executables residing on NFS
  959. mounted filesystems actually get the benefit of not hanging, in the event of
  960. paging activity, if the NFS server on which they live goes down.  This fact
  961. will also improve the performance of executables on machines short of memory.
  962. X.SH SEE ALSO
  963. untcx(1)
  964. X.SH CAVEATS
  965. Tcx will try to maintain permissions but in order to allow execution
  966. of a program on an NFS mounted filesystem to which another machine may
  967. not have root access to, it also sets the read bits on the executable
  968. corresponding to the execute bits.  This may be a slight security flaw
  969. and if it causes you problems on particular executables, do not use it on them.
  970. X.PP
  971. NFS mounted shell scripts which rely on `dirname $0` being set to something
  972. meaningful will probably break, as the TCX system can't fool the shell
  973. with a dummy argv[0] through the exec() call.
  974. X.PP
  975. Tcx requires the corresponding untcx(1) program to be available otherwise
  976. transparency is not assured.  Yell at your Systems Programmer if tcx'ed
  977. executables fail to execute.
  978. X.SH BUGS
  979. Tcx is still in beta test stage, so there are bound to be some.
  980. Please report any bugs or "patch"-style bug fixes (or new system ports)
  981. or even just suggested improvements, via email to slf@cs.mu.OZ.AU
  982. X.SH AUTHOR
  983. Stewart Forster, University Of Melbourne, 1993
  984. END_OF_FILE
  985. if test 2208 -ne `wc -c <'tcx.1'`; then
  986.     echo shar: \"'tcx.1'\" unpacked with wrong size!
  987. fi
  988. # end of 'tcx.1'
  989. fi
  990. if test -f 'tcx.c' -a "${1}" != "-c" ; then 
  991.   echo shar: Will not clobber existing file \"'tcx.c'\"
  992. else
  993. echo shar: Extracting \"'tcx.c'\" \(9587 characters\)
  994. sed "s/^X//" >'tcx.c' <<'END_OF_FILE'
  995. X/* tcx.c, Version 1.0.4, 1/4/1993 by Stewart Forster */
  996. X
  997. X/************************************************************************/
  998. X/*   Copyright (C) 1993 Stewart Forster                    */
  999. X/*  This program is free software; you can redistribute it and/or modify*/
  1000. X/*  it under the terms of the GNU General Public License as published by*/
  1001. X/*  the Free Software Foundation; either version 2, or (at your option) */
  1002. X/*  any later version.                            */
  1003. X/*                                    */
  1004. X/*  This program is distributed in the hope that it will be useful,    */
  1005. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of    */
  1006. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    */
  1007. X/*  GNU General Public License for more details.            */
  1008. X/*                                    */
  1009. X/*  You should have received a copy of the GNU General Public License    */
  1010. X/*  along with this program; if not, write to the Free Software        */
  1011. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.        */
  1012. X/************************************************************************/
  1013. X
  1014. X#include    "config.h"
  1015. X
  1016. extern    int    errno;
  1017. X
  1018. int    main(int, char *[]);
  1019. int    is_tcx(int);
  1020. int    doencode(int, int);
  1021. X
  1022. X#ifdef ULTRIX
  1023. int    is_file_local(char *);
  1024. X#endif
  1025. X
  1026. char    execname[MAXPATHLEN];
  1027. char    execpath[MAXPATHLEN];
  1028. char    dofile[MAXPATHLEN];
  1029. char    tofile[MAXPATHLEN];
  1030. char    header[MAXHEADERSIZE];
  1031. X
  1032. int
  1033. main(int argc, char *argv[])
  1034. X{
  1035. struct    stat    dostat;
  1036. char    *s;
  1037. int    perms;
  1038. int    infd, outfd;
  1039. int    len;
  1040. struct    flock    lck;
  1041. unsigned char c;
  1042. X#ifdef ULTRIX
  1043. int    islocal;
  1044. X#endif
  1045. X
  1046. X    /* Check to make sure we have an argument */
  1047. X
  1048. X    if(argc < 2)
  1049. X    {
  1050. X        (void)fprintf(stderr, "Usage: %s filename\n", argv[0]);
  1051. X        exit(-1);
  1052. X    }
  1053. X
  1054. X    if(getwd(dofile) == NULL)
  1055. X    {
  1056. X        (void)fprintf(stderr, "Get Working Directory Error: %s\n", dofile);
  1057. X        exit(-1);
  1058. X    }
  1059. X
  1060. X    if(*argv[1] == '/')
  1061. X        (void)strcpy(dofile, argv[1]);
  1062. X    else
  1063. X    {
  1064. X        (void)strcat(dofile, "/");
  1065. X        (void)strcat(dofile, argv[1]);
  1066. X    }
  1067. X    for(;;)
  1068. X    {
  1069. X        if((s = strrchr(dofile, '/')) == NULL)
  1070. X        {
  1071. X            (void)fprintf(stderr, "Internal corruption of variables!\n");
  1072. X            exit(-1);
  1073. X        }
  1074. X        s++;
  1075. X        (void)strcpy(execname, s);
  1076. X        *s = '\0';
  1077. X
  1078. X        if(chdir(dofile) < 0) { perror(dofile); exit(-1); }
  1079. X
  1080. X        if(getwd(dofile) == NULL)
  1081. X        {
  1082. X            (void)fprintf(stderr, "Get Working Directory Error: %s\n", dofile);
  1083. X            exit(-1);
  1084. X        }
  1085. X
  1086. X        if(lstat(execname, &dostat) < 0) { perror(execname); exit(-1); }
  1087. X
  1088. X        if((dostat.st_mode & S_IFMT) == S_IFLNK)
  1089. X        {
  1090. X            if((len = readlink(execname, execpath, MAXPATHLEN)) < 0)
  1091. X            {
  1092. X                perror(execname);    
  1093. X                exit(-1);
  1094. X            }
  1095. X            execpath[len] = '\0';
  1096. X            if(execpath[0] == '/')
  1097. X                (void)strcpy(dofile, execpath);
  1098. X            else
  1099. X            {
  1100. X                (void)strcat(dofile, "/");
  1101. X                (void)strcat(dofile, execpath);
  1102. X            }
  1103. X            continue;
  1104. X        }
  1105. X
  1106. X        /* If we get here, dofile is no longer pointing at a symlink */
  1107. X
  1108. X        (void)strcat(dofile, "/");
  1109. X        (void)strcat(dofile, execname);
  1110. X        break;
  1111. X    }
  1112. X
  1113. X    /* dofile from now on is the FULL pathname to the executable we're tcx-ing */
  1114. X
  1115. X    /* Just do a normal stat on dofile */
  1116. X
  1117. X    if(stat(dofile, &dostat) < 0) { perror(dofile); exit(-1); }
  1118. X
  1119. X    /* Make sure it's a regular file. If not, quit! */
  1120. X
  1121. X    if(!(dostat.st_mode & S_IFREG))
  1122. X    {
  1123. X        (void)fprintf(stderr, "Error: %s is not a regular file\n", dofile);
  1124. X        exit(-1);
  1125. X    }
  1126. X
  1127. X    /* Check permissions on file, must not be setuid or setgid */
  1128. X    /* Then check to see if it's an executable */
  1129. X
  1130. X    if(dostat.st_mode & (S_ISUID | S_ISGID))
  1131. X    {
  1132. X        (void)fprintf(stderr, "Error: Cannot compress setuid or setgid programs.\n");
  1133. X        exit(-1);
  1134. X    }
  1135. X
  1136. X    if(! (dostat.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
  1137. X    {
  1138. X        (void)fprintf(stderr, "File does have any execute bits set. Aborting.\n");
  1139. X        exit(-1);
  1140. X    }
  1141. X
  1142. X    if(dostat.st_nlink > 1)
  1143. X    {
  1144. X        (void)fprintf(stderr, "File has multiple hard links to it!  These will be destroyed\n");
  1145. X        (void)fprintf(stderr, "by this operation.  Please turn the hard links into symlinks.\n");
  1146. X        exit(-1);
  1147. X    }
  1148. X
  1149. X#ifdef ULTRIX
  1150. X    /* Test to see if file we are compressing is local or not */
  1151. X
  1152. X    if((islocal = is_file_local(dofile)) < 0)
  1153. X    {
  1154. X        perror("statfs");
  1155. X        exit(-1);
  1156. X    }
  1157. X#endif
  1158. X
  1159. X    /* Now open file we are compressing for reading. Quit if can't. */
  1160. X
  1161. X    if((infd = open(dofile, O_RDONLY)) < 0)
  1162. X    {
  1163. X        perror(dofile);
  1164. X        exit(-1);
  1165. X    }
  1166. X
  1167. X    /* Check to make sure file is not already tcx'ed */
  1168. X
  1169. X    if(is_tcx(infd))
  1170. X    {
  1171. X        (void)fprintf(stderr, "%s is already in tcx format!\n", dofile);
  1172. X        exit(0);
  1173. X    }
  1174. X
  1175. X    if(lseek(infd, 0, SEEK_SET) < 0)
  1176. X    {
  1177. X        perror("lseek");
  1178. X        exit(-1);
  1179. X    }
  1180. X
  1181. X    /* Open generation file, and try to mimic permissions */
  1182. X    /* If cannot, warn user and quit */
  1183. X
  1184. X    (void)strcpy(tofile, dofile);
  1185. X    s = strrchr(tofile, '/');
  1186. X    *s = '\0';
  1187. X    (void)strcat(tofile, "/.tcx.");
  1188. X    s = strrchr(dofile, '/');
  1189. X    s++;
  1190. X    (void)strcat(tofile, s);
  1191. X
  1192. X    lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  1193. X
  1194. X    perms = (dostat.st_mode & 0777);
  1195. X    if(perms & S_IXUSR) perms |= S_IRUSR;
  1196. X    if(perms & S_IXGRP) perms |= S_IRGRP;
  1197. X    if(perms & S_IXOTH) perms |= S_IROTH;
  1198. X    perms |= S_IWUSR;
  1199. X
  1200. X    /* Attempt to create scratch file */
  1201. X    /* Ultrix barfs on F_SETLK if file is on an NFS mount. */
  1202. X
  1203. X    if((outfd = open(tofile, O_EXCL | O_CREAT | O_WRONLY, perms)) < 0)
  1204. X    {
  1205. X#ifdef ULTRIX
  1206. X        if(islocal == 0 || errno != EEXIST)
  1207. X#else
  1208. X        if(errno != EEXIST)
  1209. X#endif
  1210. X        {
  1211. X            perror(tofile);
  1212. X            exit(-1);
  1213. X        }
  1214. X
  1215. X        /* Attempt to open and lock file that's there.  If we can't */
  1216. X        /* lock the file, someone else must be packing it, so quit. */
  1217. X        /* If we can, it must be bogus and left lying around after a*/
  1218. X        /* crash, interrupt or something. Delete file and try again.*/
  1219. X
  1220. X        if((outfd = open(tofile, O_WRONLY)) < 0)
  1221. X        {
  1222. X            perror(tofile);
  1223. X            exit(-1);
  1224. X        }
  1225. X
  1226. X        if(fcntl(outfd, F_SETLK, &lck) < 0)
  1227. X            exit(-1);
  1228. X
  1229. X        (void)unlink(tofile);    /* Unlink. Don't care if fails yet */
  1230. X        (void)close(outfd);
  1231. X        if((outfd = open(tofile, O_EXCL | O_CREAT | O_WRONLY, perms)) < 0)
  1232. X        {
  1233. X            perror(tofile);
  1234. X            exit(-1);
  1235. X        }
  1236. X    }
  1237. X
  1238. X    /* Attempt to lock tofile.  If can't then assume someone else */
  1239. X    /* is in the process of packing this file, so quit. */
  1240. X    /* Only try to lock on ULTRIX if file is local.  If not, risk */
  1241. X    /* the race condition, we have no choice!. */
  1242. X
  1243. X#ifdef ULTRIX
  1244. X    if(islocal == 1)
  1245. X#endif
  1246. X        if(fcntl(outfd, F_SETLK, &lck) < 0)
  1247. X            exit(-1);
  1248. X
  1249. X    /* Do a chmod (Just to be sure - in case of user umask affecting open) */
  1250. X
  1251. X    if(chmod(tofile, perms) < 0)
  1252. X    {
  1253. X        (void)fprintf(stderr, "Cannot set proper permissions on scratch file %s\n", tofile);
  1254. X        (void)close(infd);
  1255. X        (void)close(outfd);
  1256. X        if(unlink(tofile) < 0)
  1257. X            (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  1258. X        exit(-1);
  1259. X    }
  1260. X
  1261. X    if(chown(tofile, dostat.st_uid, dostat.st_gid) < 0)
  1262. X    {
  1263. X        (void)fprintf(stderr, "Cannot set proper ownership on scratch file\n");
  1264. X        (void)close(infd);
  1265. X        (void)close(outfd);
  1266. X        if(unlink(tofile) < 0)
  1267. X            (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  1268. X        exit(-1);
  1269. X    }
  1270. X
  1271. X    /* Spit out header and start encoding executable */
  1272. X
  1273. X    (void)sprintf(header, "#!%s\n", PATHUNTCX);
  1274. X    if(write(outfd, header, strlen(header)) < 0) { (void)perror("write"); exit(-1); }
  1275. X
  1276. X    c = 0;    if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  1277. X    c = 76;    if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  1278. X    c = 193; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  1279. X    c = 13;    if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  1280. X    c = 138; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  1281. X
  1282. X    if(doencode(infd, outfd) != 0)
  1283. X    {
  1284. X        (void)fprintf(stderr, "Compression failed\n");
  1285. X        if(unlink(tofile) < 0)
  1286. X            (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  1287. X        exit(-1);
  1288. X    }
  1289. X
  1290. X    (void)close(infd);
  1291. X
  1292. X    if((infd = open(dofile, O_WRONLY)) <= 0)
  1293. X    {
  1294. X        perror(dofile);
  1295. X        if(unlink(tofile) < 0)
  1296. X            (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  1297. X        exit(-1);
  1298. X    }
  1299. X
  1300. X#ifdef ULTRIX
  1301. X    if(islocal == 1)
  1302. X#endif
  1303. X        if(fcntl(infd, F_SETLK, &lck) < 0)
  1304. X        {
  1305. X            if(unlink(tofile) < 0)
  1306. X                (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  1307. X            exit(-1);
  1308. X        }
  1309. X
  1310. X    /* Rename() compressed version to original */
  1311. X
  1312. X    if(rename(tofile, dofile) < 0)
  1313. X    {
  1314. X        perror(dofile);
  1315. X        if(unlink(tofile) < 0)
  1316. X            (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  1317. X        exit(-1);
  1318. X    }
  1319. X
  1320. X    /* Close files and hence locks */
  1321. X
  1322. X    (void)close(infd);
  1323. X    (void)close(outfd);
  1324. X
  1325. X    /* All done! Bye, bye. */
  1326. X
  1327. X    return(0);
  1328. X}
  1329. X
  1330. X
  1331. int
  1332. is_tcx(int fd)
  1333. X{
  1334. int     i;
  1335. unsigned char   c;
  1336. X
  1337. X        for(i = 0; i < MAXHEADERSIZE; i++)
  1338. X                if(read(fd, &c, 1) < 1 || c == 0)
  1339. X                        break;
  1340. X        if((i >= MAXHEADERSIZE) || read(fd, &c, 1) < 1  || c != 76 || read(fd, &c, 1) < 1  || c != 193
  1341. X            || read(fd, &c, 1) < 1  || c != 13 || read(fd, &c, 1) < 1  || c != 138 )
  1342. X                return 0;
  1343. X        return 1;
  1344. X} /* is_tcx */
  1345. X
  1346. X
  1347. int
  1348. doencode(int infd, int outfd)
  1349. X{
  1350. int    pid;
  1351. X#if defined(AIX) || defined(IRIX)
  1352. int    status;
  1353. X#else
  1354. union wait status;
  1355. X#endif
  1356. X
  1357. X    pid = fork();
  1358. X    if(pid < 0) return -1;
  1359. X    if(pid == 0)
  1360. X    {
  1361. X        if(dup2(infd, 0) < 0)    exit(-1);    /* Attach infd to stdin */
  1362. X        (void)close(infd);
  1363. X        if(dup2(outfd, 1) < 0)    exit(-1);    /* Attach outfd to stdout */
  1364. X        (void)close(outfd);
  1365. X#ifdef PACKEROPTS
  1366. X        (void)execl(PATHPACKER, PATHPACKER, PACKEROPTS, (char *)0);
  1367. X#else
  1368. X        (void)execl(PATHPACKER, PATHPACKER, (char *)0);
  1369. X#endif
  1370. X        exit(-1);
  1371. X    }
  1372. X    else
  1373. X        pid = wait(&status);
  1374. X    return WEXITSTATUS(status);
  1375. X} /* doencode */
  1376. X
  1377. X
  1378. X#ifdef ULTRIX
  1379. int
  1380. is_file_local(char *path)
  1381. X{
  1382. struct  fs_data fsbuf;
  1383. X
  1384. X        if(statfs(path, &fsbuf) < 1)     /* Returns 0 on "NOT MOUNTED" */
  1385. X                return -1;
  1386. X
  1387. X        /* NFS Version 2 returns -1 or 0 for both gfree, and gtot */
  1388. X        /* to a client, so return false on this condition. */
  1389. X
  1390. X        if((fsbuf.fd_req.gfree <= 0) && (fsbuf.fd_req.gtot <= 0))
  1391. X                return 0;
  1392. X    return 1;
  1393. X} /* is_file_local */
  1394. X#endif
  1395. END_OF_FILE
  1396. if test 9587 -ne `wc -c <'tcx.c'`; then
  1397.     echo shar: \"'tcx.c'\" unpacked with wrong size!
  1398. fi
  1399. # end of 'tcx.c'
  1400. fi
  1401. if test -f 'untcx.1' -a "${1}" != "-c" ; then 
  1402.   echo shar: Will not clobber existing file \"'untcx.1'\"
  1403. else
  1404. echo shar: Extracting \"'untcx.1'\" \(1639 characters\)
  1405. sed "s/^X//" >'untcx.1' <<'END_OF_FILE'
  1406. X.TH UNTCX 1 "19 March 1993"
  1407. X.UC Melb
  1408. X.SH NAME
  1409. untcx \- Uncompress or execute tcx executables
  1410. X.SH SYNOPSIS
  1411. untcx [-x | -u] filename [args]
  1412. X.SH DESCRIPTION
  1413. X\fBUntcx\fP performs three functions.  Firstly used as listed above, it
  1414. will uncompress an executable compressed with tcx(1), if such compression
  1415. is no longer desired.  If the \fB-x\fP option is specified, this will force
  1416. untcx to execute \fBfilename\fP, with \fBargs\fP as command line arguments.
  1417. X.PP
  1418. If the \fB-u\fP option is given, this forces untcx into plain decompression
  1419. of \fBfilename\fP.  Note, that while this is the default mode of operation for
  1420. users other than root, it is required if the invoking user is root.  Under the
  1421. LINUX operating system, the -u option is ALWAYS required by any user if that
  1422. user wishes to explicitly uncompress an executable.
  1423. X.PP
  1424. Secondly it is the tool which performs and transparant uncompression
  1425. and execution of executables compressed with tcx(1).  This mode of
  1426. operation is never directly seen by the user (otherwise it wouldn't
  1427. be transparent would it!).
  1428. X.PP
  1429. Thirdly it invokes itself in a daemon mode which will keep track of
  1430. all executables operating withing the tcx system, to allow for
  1431. transparent recompression of executables that have been uncompressed
  1432. in the process of being invoked.  This mode of operation is also
  1433. transparent to the user.
  1434. X.SH SEE ALSO
  1435. tcx(1)
  1436. X.SH BUGS
  1437. Untcx is still in beta test stage, so there are bound to be some.
  1438. Please report any bugs or "patch"-style bug fixes (or new system ports)
  1439. or even just suggested improvements, via email to slf@cs.mu.OZ.AU
  1440. X.SH AUTHOR
  1441. Stewart Forster, University Of Melbourne, 1993
  1442. END_OF_FILE
  1443. if test 1639 -ne `wc -c <'untcx.1'`; then
  1444.     echo shar: \"'untcx.1'\" unpacked with wrong size!
  1445. fi
  1446. # end of 'untcx.1'
  1447. fi
  1448. if test -f 'untcx.c' -a "${1}" != "-c" ; then 
  1449.   echo shar: Will not clobber existing file \"'untcx.c'\"
  1450. else
  1451. echo shar: Extracting \"'untcx.c'\" \(31646 characters\)
  1452. sed "s/^X//" >'untcx.c' <<'END_OF_FILE'
  1453. X/* untcx.c, Version 1.0.5, 5/4/1993 by Stewart Forster */
  1454. X
  1455. X/************************************************************************/
  1456. X/*   Copyright (C) 1993 Stewart Forster                    */
  1457. X/*  This program is free software; you can redistribute it and/or modify*/
  1458. X/*  it under the terms of the GNU General Public License as published by*/
  1459. X/*  the Free Software Foundation; either version 2, or (at your option) */
  1460. X/*  any later version.                            */
  1461. X/*                                    */
  1462. X/*  This program is distributed in the hope that it will be useful,    */
  1463. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of    */
  1464. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    */
  1465. X/*  GNU General Public License for more details.            */
  1466. X/*                                    */
  1467. X/*  You should have received a copy of the GNU General Public License    */
  1468. X/*  along with this program; if not, write to the Free Software        */
  1469. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.        */
  1470. X/************************************************************************/
  1471. X
  1472. X#include    "config.h"
  1473. X
  1474. typedef struct path
  1475. X{
  1476. X    char    path[MAXPATHLEN]; /* Pathname to file */
  1477. X#ifdef UNPACK_IN_PLACE
  1478. X    int    pid;        /* Process id compressing file */
  1479. X    int    local;        /* Is file local? */
  1480. X#endif
  1481. X    int    atime;        /* Time last known to be busy */
  1482. X    int    ctime;        /* Inode modification time */
  1483. X    struct    path    *next;    /* Next structure */
  1484. X} path;
  1485. X
  1486. X#if defined(SUNOS)
  1487. X#define    MAXOPENFILES    4096
  1488. X#define    PIHASH(a, b)    (((a) + (b)) % MAXOPENFILES)
  1489. X
  1490. typedef struct pstat
  1491. X{
  1492. X    int    dev;
  1493. X    int    ino;
  1494. X    int    cnt;
  1495. X    struct    pstat    *next;
  1496. X} pstat;
  1497. X
  1498. pstat    parr[MAXOPENFILES];
  1499. pstat    *pihash[MAXOPENFILES];
  1500. void    update_pstat_info();
  1501. X#endif
  1502. X
  1503. extern    int    errno;
  1504. path    *worklist = NULL, *freelist = NULL;
  1505. X
  1506. X
  1507. char    logpath[MAXPATHLEN], logtmppath[MAXPATHLEN], lockpath[MAXPATHLEN];
  1508. X
  1509. char    cwd[MAXPATHLEN];    /* Save of current working directory */
  1510. char    realdir[MAXPATHLEN];    /* Real directory packed executable lives in */
  1511. char    execname[MAXPATHLEN];    /* Name of packed/target executable */
  1512. char    execpath[MAXPATHLEN];    /* Full path name of packed executable */
  1513. char    untcxtmp[MAXPATHLEN];    /* Temporary unpack pathname */
  1514. char    tcxtarg[MAXPATHLEN];    /* Target path name of unpacked executable */
  1515. char    linkpath[MAXPATHLEN];    /* Pathname of symlink to executable */
  1516. X
  1517. void    untcx_and_exec_local(char *, char *, char *[]);
  1518. void    untcx_and_exec_nfs(char *, char *, char *, char *[]);
  1519. int    try_to_exec(char *, char *, char *[]);
  1520. void    check_tcxd_mode();
  1521. X#ifdef UNPACK_IN_PLACE
  1522. SIGTYPE    tcxd_reaper();
  1523. X#endif
  1524. void    just_untcx(char *, char *);
  1525. int    scan_logtail(int);
  1526. int    is_dir_local(char *);
  1527. int    is_tcx(int);
  1528. int    dodecode(int, int);
  1529. char    *newargs[1024];
  1530. X#if defined(ULTRIX)
  1531. int    usleep(int);
  1532. int    usleep_sig();
  1533. X#endif
  1534. X
  1535. int
  1536. main(int argc, char *argv[])
  1537. X{
  1538. char    *c;            /* String manipulation pointers */
  1539. struct    stat    dostat;    /* Stat buffer */
  1540. int    i, isinterp, len;
  1541. X#ifdef UNPACK_IN_PLACE
  1542. int    local;
  1543. X#endif
  1544. X
  1545. X    if(argc < 2)
  1546. X    {
  1547. X        (void)fprintf(stderr, "Usage: %s filename\n", argv[0]);
  1548. X        exit(-1);
  1549. X    }
  1550. X
  1551. X    /* Re-exec if not root and pass -x along on the command line. */
  1552. X    /* If it's there when we restart and we're still not root, then */
  1553. X    /* avoid an exec loop by quitting with a warning. */
  1554. X
  1555. X    if(geteuid() != 0)
  1556. X    {
  1557. X#ifndef LINUX
  1558. X        if(strcmp(argv[1], "-x") == 0)
  1559. X#endif
  1560. X        {
  1561. X            (void)fprintf(stderr, "Error: untcx is not installed setuid to root!\n");
  1562. X            (void)fprintf(stderr, "Contact your systems administrator\n");
  1563. X            exit(-1);
  1564. X        }
  1565. X
  1566. X        /* Push -x into argv[1] and shift rest of args along */
  1567. X
  1568. X        newargs[0] = argv[0];
  1569. X        newargs[1] = "-x";
  1570. X        for(i = 1; i < argc; i++) newargs[i+1] = argv[i];
  1571. X        newargs[i + 1] = (char *)NULL;
  1572. X        if(execv(PATHUNTCX, newargs) < 0)
  1573. X            perror("exec");
  1574. X
  1575. X        /* exec failed! Warn user and quit */
  1576. X
  1577. X        (void)fprintf(stderr, "Unable to invoke interpreter as root\n");
  1578. X        exit(-1);
  1579. X    }
  1580. X
  1581. X    if(strcmp(argv[1], "-x") == 0)
  1582. X    {
  1583. X        for(i = 1; i < (argc - 1); i++) argv[i] = argv[i+1];
  1584. X        argv[i] = (char *)NULL;
  1585. X        --argc;
  1586. X        isinterp = 1;
  1587. X    }
  1588. X    else
  1589. X    if(strcmp(argv[1], "-u") == 0)
  1590. X    {
  1591. X        for(i = 1; i < (argc - 1); i++) argv[i] = argv[i+1];
  1592. X        argv[i] = (char *)NULL;
  1593. X        --argc;
  1594. X        isinterp = 0;
  1595. X    }
  1596. X    else
  1597. X#if defined(LINUX)
  1598. X        isinterp = 1;
  1599. X#else
  1600. X    if(getuid() == 0)
  1601. X        isinterp = 1;
  1602. X    else
  1603. X        isinterp = 0;
  1604. X#endif
  1605. X
  1606. X    /* Copy argv[1] to argv[0] for obsolete stuff (and IRIX) */
  1607. X
  1608. X    argv[0] = argv[1];
  1609. X
  1610. X    /* Setup to catch all undesirable signals */
  1611. X
  1612. X    (void)signal(SIGINT, SIG_IGN);
  1613. X    (void)signal(SIGHUP, SIG_IGN);
  1614. X    (void)signal(SIGTSTP, SIG_IGN);
  1615. X    (void)signal(SIGALRM, SIG_IGN);
  1616. X    (void)signal(SIGQUIT, SIG_IGN);
  1617. X    (void)signal(SIGTERM, SIG_IGN);
  1618. X
  1619. X    /* Set global paths */
  1620. X
  1621. X    (void)sprintf(logpath, "%s/log", ENFSDIR);
  1622. X    (void)sprintf(logtmppath, "%s/logtmp", ENFSDIR);
  1623. X    (void)sprintf(lockpath, "%s/.lock", ENFSDIR);
  1624. X
  1625. X    /* Check and start tcxd as required */
  1626. X
  1627. X    check_tcxd_mode();
  1628. X
  1629. X    /* Go to the uid of invoking user.  Resolve through symbolic links */
  1630. X    /* as to what the real pathname of the executable is. */
  1631. X
  1632. X#ifdef AIX
  1633. X    if(seteuid(getuid()) < 0) { perror("seteuid"); exit(-1); }
  1634. X#else
  1635. X    if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  1636. X#endif
  1637. X
  1638. X    /* Grab argv[0] and resolve to full path name via getwd() */
  1639. X
  1640. X    if(getwd(cwd) == NULL)
  1641. X    {
  1642. X        (void)fprintf(stderr, "Get Working Directory Error: %s\n", cwd);
  1643. X        exit(-1);
  1644. X    }
  1645. X
  1646. X    if(*argv[0] == '/')
  1647. X        (void)strcpy(realdir, argv[0]);
  1648. X    else
  1649. X        (void)sprintf(realdir, "%s/%s", cwd, argv[0]);
  1650. X    for(;;)
  1651. X    {
  1652. X        if((c = strrchr(realdir, '/')) == NULL)
  1653. X        {    /* Should never happen, BUT... */
  1654. X            (void)fprintf(stderr, "Help! Internal corruption of variables!\n");
  1655. X            exit(-1);
  1656. X        }
  1657. X        c++;
  1658. X        (void)strcpy(execname, c);
  1659. X        *c = '\0';
  1660. X
  1661. X        if(chdir(realdir) < 0)    /* Oops. Failed. Report and quit. */
  1662. X        {
  1663. X            perror(realdir);
  1664. X            exit(-1);
  1665. X        }
  1666. X
  1667. X        if(getwd(realdir) == NULL)
  1668. X        {
  1669. X            (void)fprintf(stderr, "Get Working Directory Error: %s\n", cwd);
  1670. X            exit(-1);
  1671. X        }
  1672. X
  1673. X        /* Do lstat executable from here. If not a link, go on, else */
  1674. X        /* read the value of the link, and append it to realdir if */
  1675. X        /* it doesn't begin with a /, other just copy it to realdir */
  1676. X        /* and cycle through the loop again. */
  1677. X
  1678. X        if(lstat(execname, &dostat) < 0)
  1679. X        {
  1680. X            perror(execname);
  1681. X            exit(-1);
  1682. X        }
  1683. X
  1684. X        if((dostat.st_mode & S_IFMT) == S_IFLNK)
  1685. X        {
  1686. X            if((len = readlink(execname, execpath, MAXPATHLEN)) < 0)
  1687. X            {
  1688. X                perror(execname);
  1689. X                exit(-1);
  1690. X            }
  1691. X            execpath[len] = '\0';
  1692. X            if(execpath[0] == '/')
  1693. X                (void)strcpy(realdir, execpath);
  1694. X            else
  1695. X            {
  1696. X                (void)strcat(realdir, "/");
  1697. X                (void)strcat(realdir, execpath);
  1698. X            }
  1699. X            continue;
  1700. X        }
  1701. X
  1702. X        if(!(dostat.st_mode & S_IFREG))
  1703. X        {
  1704. X            (void)fprintf(stderr, "Error: Not an executable file - %s/%s\n", realdir, execname);
  1705. X            exit(-1);
  1706. X        }
  1707. X
  1708. X        /* Now do a statfs on realdir.  If it's on an NFS mounted filesystem we */
  1709. X        /* will need to unpack to ENFSDIR, otherwise we can unpack it in place, */
  1710. X
  1711. X#ifdef UNPACK_IN_PLACE
  1712. X        if((local = is_dir_local(realdir)) < 0)
  1713. X            exit(-1);
  1714. X        if(dostat.st_nlink > 1)    /* Unpack to ENFSDIR if file is linked */
  1715. X            local = 0;
  1716. X#endif
  1717. X
  1718. X        break;
  1719. X    }
  1720. X
  1721. X    /* Return to the original invocation directory */
  1722. X
  1723. X    if(chdir(cwd) < 0)
  1724. X    {
  1725. X        perror(cwd);
  1726. X        exit(-1);
  1727. X    }
  1728. X
  1729. X#ifdef AIX
  1730. X    if(seteuid(0) < 0) { perror("seteuid"); exit(-1); }
  1731. X#else
  1732. X    if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  1733. X#endif
  1734. X
  1735. X    /* Now check if last components of argv[0] and argv[1] are equal */
  1736. X    /* If not, we are invoked just to decompress something, not to */
  1737. X    /* execute it.  Just attempt an uncompress as the user */
  1738. X
  1739. X    if(isinterp == 0)
  1740. X    {
  1741. X#if defined(IRIX) || defined(AIX)
  1742. X        if(setuid(getuid()) < 0) { perror("setuid"); exit(-1); }
  1743. X#else
  1744. X        if(setreuid(getuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  1745. X#endif
  1746. X        (void)sprintf(tcxtarg, "%s/%s", realdir, execname);
  1747. X        (void)sprintf(untcxtmp, "%s/.untcx.%s", realdir, execname);
  1748. X        just_untcx(tcxtarg, untcxtmp);
  1749. X        exit(0);
  1750. X    }
  1751. X
  1752. X#ifdef UNPACK_IN_PLACE
  1753. X    /* Try to do a local execute. If it returns, it means failure. */
  1754. X
  1755. X    if(local)
  1756. X    {
  1757. X        (void)sprintf(tcxtarg, "%s/%s", realdir, execname);
  1758. X        (void)sprintf(untcxtmp, "%s/.untcx.%s", realdir, execname);
  1759. X        untcx_and_exec_local(tcxtarg, untcxtmp, &(argv[1]));
  1760. X    }
  1761. X#endif
  1762. X
  1763. X    /* We get this far if file is not local, or the local execution */
  1764. X    /* failed for some reason like shortage of disk space. Attempt */
  1765. X    /* to unpack program to /tmp and go from there. */
  1766. X
  1767. X    for(c = realdir; *c ; c++)
  1768. X        if(*c == '/')
  1769. X            *c = '=';
  1770. X    (void)sprintf(tcxtarg, "%s/%s", ENFSDIR, realdir);
  1771. X    if(mkdir(tcxtarg, 0777) < 0)
  1772. X        if(errno != EEXIST)
  1773. X        {
  1774. X            perror(tcxtarg);
  1775. X            exit(-1);
  1776. X        }
  1777. X    (void)chmod(tcxtarg, 0777);
  1778. X    (void)strcat(tcxtarg,"/");
  1779. X    (void)strcat(tcxtarg, execname);
  1780. X    (void)sprintf(untcxtmp, "%s/%s/.untcx.%s", ENFSDIR, realdir, execname);
  1781. X
  1782. X    untcx_and_exec_nfs(argv[0], untcxtmp, tcxtarg, &(argv[1]));
  1783. X
  1784. X    /* :-(  We only get this far if everything has failed. Exit with failure */
  1785. X
  1786. X    return(-1);
  1787. X} /* main */
  1788. X
  1789. X
  1790. void
  1791. check_tcxd_mode()
  1792. X{
  1793. char    *s, spid[32];
  1794. int    infd, logfd, lkfd, lasttime = 0, timer;
  1795. XFILE    *logfp;
  1796. path    *curr, *prev;
  1797. struct    stat    sb;    /* Stat buffer */
  1798. struct    flock    lck;    /* File lock structure */
  1799. int    lastoff;
  1800. X
  1801. X    /* Check if we're root. If not, go home */
  1802. X
  1803. X    if(geteuid() != 0)
  1804. X        return;
  1805. X
  1806. X    /* Try to create emergency/NFS execute directory and set it's permissions */
  1807. X    /* It's not important yet if we can't at this stage. */
  1808. X
  1809. X    (void)mkdir(ENFSDIR, 01777);
  1810. X    (void)chmod(ENFSDIR, 01777);
  1811. X
  1812. X    /* Attempt to create ENFSDIR/.lock  If can't, just return. */
  1813. X
  1814. X    if((lkfd = open(lockpath, O_CREAT | O_RDONLY, 0600)) < 0)
  1815. X        return;
  1816. X
  1817. X    /* Attempt to read lock ENFSDIR/.lock If can't, we assume the tcxd */
  1818. X    /* is already running. Return. */
  1819. X
  1820. X    lck.l_type = F_RDLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  1821. X    if(fcntl(lkfd, F_SETLK, &lck) < 0)
  1822. X    {
  1823. X        (void)close(lkfd);
  1824. X        return;
  1825. X    }
  1826. X
  1827. X    /* Close lkfd and hence the lock on it, fork() and return */
  1828. X
  1829. X    (void)close(lkfd);
  1830. X    if(fork() != 0)    /* On parent or fork error, just return */
  1831. X        return;
  1832. X
  1833. X    /* No errors to user at this point */
  1834. X
  1835. X    (void)fclose(stderr); (void)close(2);
  1836. X    (void)fclose(stdout); (void)close(1);
  1837. X    (void)open("/dev/null", O_WRONLY);
  1838. X    (void)open("/dev/null", O_WRONLY);    /* Don't really care */
  1839. X
  1840. X    /* Make ourselves nice and rooted */
  1841. X
  1842. X#ifndef AIX
  1843. X#if defined(IRIX)
  1844. X    if(setuid(geteuid()) < 0) exit(-1);
  1845. X#else
  1846. X    if(setreuid(geteuid(), geteuid()) < 0) exit(-1);
  1847. X#endif
  1848. X#endif
  1849. X
  1850. X    /* Check if we're root again. If not, exit */
  1851. X
  1852. X    if(geteuid() != 0)
  1853. X        exit(-1);
  1854. X
  1855. X    /* Change directory to ENFSDIR to prevent hanging on NFS server crashes */
  1856. X
  1857. X    if(chdir(ENFSDIR) < 0)
  1858. X        exit(-1);
  1859. X
  1860. X    /* Lock the server lock file to prevent more than 1 starting up */
  1861. X
  1862. X    if((lkfd = open(lockpath, O_WRONLY | O_TRUNC)) < 0)
  1863. X        exit(-1);
  1864. X    lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  1865. X    if(fcntl(lkfd, F_SETLK, &lck) < 0)
  1866. X        exit(-1);
  1867. X
  1868. X    /* Write our process id to the lock file. Don't really care if fails. */
  1869. X
  1870. X    (void)sprintf(spid, "%d\n", getpid());
  1871. X    (void)write(lkfd, spid, strlen(spid));
  1872. X
  1873. X#ifdef UNPACK_IN_PLACE
  1874. X    /* setup our child process reaper */
  1875. X
  1876. X    (void)signal(SIGCHLD, tcxd_reaper);
  1877. X#endif
  1878. X
  1879. X    /* Read in log file if it's there in case of crashes */
  1880. X
  1881. X    if((lastoff = scan_logtail(0)) < 0)
  1882. X        (void)creat(logpath, 0600);
  1883. X
  1884. X    /* Loop doing tasks at hand */
  1885. X
  1886. X    for(lastoff = 0;;)
  1887. X    {
  1888. X        for(timer = 0; timer < SCANRATE; timer++, (void)sleep(1))
  1889. X        {
  1890. X            if(stat(logpath, &sb) < 0)
  1891. X                continue;
  1892. X
  1893. X            /* Don't check if not updated, but do on last time */
  1894. X
  1895. X            if(sb.st_mtime <= lasttime)
  1896. X                continue;
  1897. X            lasttime = sb.st_mtime;
  1898. X
  1899. X            lastoff = scan_logtail(lastoff);
  1900. X        }
  1901. X
  1902. X#if defined(SUNOS)
  1903. X        update_pstat_info();
  1904. X#endif
  1905. X
  1906. X        for(prev = NULL, curr = worklist; curr != NULL; prev = curr, curr = curr->next)
  1907. X        {
  1908. X            /* Stat file. If not accessed within LOCALTIMOUT secs */
  1909. X            /* for a local file, or ENFSTIMEOUT secs for an NFS file */
  1910. X            /* we consider it a candidate for compression. */
  1911. X
  1912. X            if(stat(curr->path, &sb) < 0)
  1913. X            {
  1914. X                if(lstat(curr->path, &sb) >= 0)
  1915. X                {
  1916. X                    (void)unlink(curr->path);    /* Was symlink. Unlink it! */
  1917. X                    s = strrchr(curr->path, '/');
  1918. X                    *s = '\0';
  1919. X                    (void)rmdir(curr->path);
  1920. X                }
  1921. X                (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  1922. X                curr->next = freelist; freelist = curr;
  1923. X                (prev == NULL) ? (curr = worklist) : (curr = prev);
  1924. X                if(curr == NULL) break;
  1925. X                continue;
  1926. X            }
  1927. X
  1928. X            if(sb.st_atime > curr->atime)
  1929. X                curr->atime = sb.st_atime;
  1930. X
  1931. X#ifdef UNPACK_IN_PLACE
  1932. X            if(curr->local == 1 && (time(NULL) - curr->atime) < LOCALTIMEOUT)
  1933. X                continue;
  1934. X            if(curr->local == 0 && (time(NULL) - curr->atime) < ENFSTIMEOUT)
  1935. X                continue;
  1936. X#else
  1937. X            if((time(NULL) - curr->atime) < ENFSTIMEOUT)
  1938. X                continue;
  1939. X#endif
  1940. X
  1941. X#if defined(IRIX) || defined(DEC) || defined(AIX) || defined(LINUX)
  1942. X            /* Attempt to open file for writing, if it fails with ETXTBSY */
  1943. X            /* then update access times and continue, otherwise it is a */
  1944. X            /* candidate for recompression. */
  1945. X
  1946. X            if((infd = open(curr->path, O_WRONLY)) < 0)
  1947. X            {
  1948. X                if(errno != ETXTBSY)
  1949. X                {
  1950. X                    if(lstat(curr->path, &sb) >= 0)
  1951. X                    {
  1952. X                        (void)unlink(curr->path);    /* Was symlink. Unlink it! */
  1953. X                        s = strrchr(curr->path, '/');
  1954. X                        *s = '\0';
  1955. X                        (void)rmdir(curr->path);
  1956. X                    }
  1957. X                    (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  1958. X                    curr->next = freelist; freelist = curr;
  1959. X                    (prev == NULL) ? (curr = worklist) : (curr = prev);
  1960. X                    if(curr == NULL) break;
  1961. X                    continue;
  1962. X                }
  1963. X                curr->atime = time(NULL);
  1964. X                continue;
  1965. X            }
  1966. X            (void)close(infd);
  1967. X#endif
  1968. X
  1969. X#if defined(SUNOS)
  1970. X        {
  1971. X        pstat    *pc;
  1972. X        int    found = 0;
  1973. X
  1974. X            for(pc = pihash[PIHASH(sb.st_dev, sb.st_ino)]; pc != NULL; pc = pc->next)
  1975. X                if(pc->dev == sb.st_dev && pc->ino == sb.st_ino)
  1976. X                {
  1977. X                    if(pc->cnt < 2) break;
  1978. X                    curr->atime = time(NULL);
  1979. X                    found = 1;
  1980. X                    break;
  1981. X                }
  1982. X            if(found) continue;
  1983. X        }
  1984. X#endif
  1985. X
  1986. X#ifdef UNPACK_IN_PLACE
  1987. X            if(curr->local == -1)    /* Compression completed */
  1988. X            {
  1989. X                (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  1990. X                curr->next = freelist; freelist = curr;
  1991. X                (prev == NULL) ? (curr = worklist) : (curr = prev);
  1992. X                if(curr == NULL) break;
  1993. X                continue;
  1994. X            }
  1995. X
  1996. X            if(curr->pid > 0)
  1997. X                continue;
  1998. X
  1999. X            if(curr->local == 1)
  2000. X            {
  2001. X                /* Check inode modification times. If target is */
  2002. X                /* newer than what we know, forget it. */
  2003. X
  2004. X                if(sb.st_ctime > curr->ctime)
  2005. X                {
  2006. X                    (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  2007. X                    curr->next = freelist; freelist = curr;
  2008. X                    (prev == NULL) ? (curr = worklist) : (curr = prev);
  2009. X                    if(curr == NULL) break;
  2010. X                    continue;
  2011. X                }
  2012. X
  2013. X                /* Fork and compress program */
  2014. X
  2015. X                curr->pid = fork();
  2016. X                if(curr->pid != 0) continue;
  2017. X
  2018. X                /* Here we must be the child */
  2019. X                /* Close stdio stuff and reopen to /dev/null */
  2020. X
  2021. X                (void)close(2);
  2022. X                (void)close(1);
  2023. X                (void)close(0);
  2024. X                (void)open("/dev/null", O_RDONLY);
  2025. X                (void)open("/dev/null", O_WRONLY);
  2026. X                (void)open("/dev/null", O_WRONLY);
  2027. X                (void)execl(PATHTCX, "tcx", curr->path, (char *)0);
  2028. X                exit(-1);
  2029. X            }
  2030. X#endif
  2031. X
  2032. X            /* At this point, file is in ENFSDIR. Delete it */
  2033. X
  2034. X            (void)unlink(curr->path);
  2035. X            s = strrchr(curr->path, '/');
  2036. X            *s = '\0';
  2037. X            (void)rmdir(curr->path);
  2038. X
  2039. X            (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  2040. X            curr->next = freelist; freelist = curr;
  2041. X            (prev == NULL) ? (curr = worklist) : (curr = prev);
  2042. X            if(curr == NULL) break;
  2043. X        } /* for */
  2044. X
  2045. X        /* Update log file in case of crashes */
  2046. X
  2047. X        lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  2048. X
  2049. X        /* Do one final read in case someone has modified during */
  2050. X        /* the scan sequence. */
  2051. X
  2052. X        (void)scan_logtail(lastoff);
  2053. X
  2054. X        if((logfp = fopen(logtmppath, "w")) == NULL)
  2055. X            continue;
  2056. X        for(curr = worklist; curr != NULL; curr = curr->next)
  2057. X            (void)fprintf(logfp, "%s\n", curr->path);
  2058. X        (void)fclose(logfp);
  2059. X
  2060. X        /* Try for 20 times to lock file, sleep 5/100ths secs b/w tries */
  2061. X
  2062. X        for(timer = 0; timer < 20; timer++, PUSLEEP(50000))
  2063. X        {
  2064. X            if((logfd = open(logpath, O_WRONLY)) < 0)
  2065. X                continue;
  2066. X            if(fcntl(logfd, F_SETLK, &lck) < 0)
  2067. X            {    (void)close(logfd); continue;    }
  2068. X
  2069. X            (void)rename(logtmppath, logpath);
  2070. X            if(stat(logpath, &sb) < 0)
  2071. X                lastoff = 0;
  2072. X            else
  2073. X                lastoff = sb.st_size;
  2074. X            (void)close(logfd);
  2075. X            break;
  2076. X        }
  2077. X    } /* for */
  2078. X} /* check_tcxd_mode */
  2079. X
  2080. X
  2081. X#ifdef UNPACK_IN_PLACE
  2082. SIGTYPE
  2083. tcxd_reaper()
  2084. X{
  2085. X#if defined(AIX)
  2086. int    state;
  2087. X#else
  2088. union wait state;
  2089. X#endif
  2090. int    pid;
  2091. path    *curr;
  2092. X
  2093. X    while((pid = wait3(&state, WNOHANG, 0)) > 0)
  2094. X        for(curr = worklist; curr != NULL; curr = curr->next)
  2095. X            if(curr->pid == pid)
  2096. X            {
  2097. X                curr->pid = -1;
  2098. X                if(WIFEXITED(state) && WEXITSTATUS(state) == 0)
  2099. X                    curr->local = -1;
  2100. X                break;
  2101. X            }
  2102. X#if defined(IRIX) || defined(AIX)
  2103. X    (void)signal(SIGCHLD, tcxd_reaper);
  2104. X#endif
  2105. X} /* tcxd_reaper */
  2106. X#endif
  2107. X
  2108. X
  2109. X#ifdef UNPACK_IN_PLACE
  2110. void
  2111. untcx_and_exec_local(char *expath, char *untemp, char *argv[])
  2112. X{
  2113. struct    stat    tostat;    /* Stat buffer to check on lengths */
  2114. int    owner, group;
  2115. int    perms;        /* Saved permissions to restore on target exec */
  2116. int    infd, outfd;    /* In and out file descriptors */
  2117. struct    flock    lck;    /* File lock structure */
  2118. X
  2119. X    /* In this function argv[0] and expath would normally be the same */
  2120. X    /* BUT, if argv[0] is a symlink to expath, we want to invoke it */
  2121. X    /* like that, and not via expath. */
  2122. X
  2123. X    /* Stat executable and grab permissions */
  2124. X
  2125. X    if(stat(expath, &tostat) < 0)
  2126. X    {
  2127. X        perror(argv[0]);
  2128. X        exit(-1);
  2129. X    }
  2130. X    perms = (tostat.st_mode & 0777);
  2131. X    owner = tostat.st_uid;
  2132. X    group = tostat.st_gid;
  2133. X
  2134. X    for(;;PUSLEEP(10000))
  2135. X    {
  2136. X        if((infd = open(expath, O_RDWR)) < 0)
  2137. X        {
  2138. X            if(errno != ETXTBSY)
  2139. X            {
  2140. X                (void)fprintf(stderr, "Cannot write to %s\n", expath);
  2141. X                exit(-1);
  2142. X            }
  2143. X            if((infd = open(expath, O_RDONLY)) < 0)
  2144. X                continue;
  2145. X            (void)close(infd);
  2146. X            if(try_to_exec(expath, argv[0], argv) < 0)
  2147. X                exit(-1);
  2148. X            continue;
  2149. X        }
  2150. X
  2151. X        lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  2152. X        if(fcntl(infd, F_SETLK, &lck) < 0)
  2153. X        {
  2154. X            if(fcntl(infd, F_GETLK, &lck) < 0 || lck.l_type != F_RDLCK)
  2155. X            { (void)close(infd); continue; }
  2156. X            (void)close(infd);
  2157. X            if(try_to_exec(expath, argv[0], argv) < 0)
  2158. X                exit(-1);
  2159. X            continue;
  2160. X        }
  2161. X
  2162. X        if(! is_tcx(infd))
  2163. X        {
  2164. X            (void)close(infd);
  2165. X            if(try_to_exec(expath, argv[0], argv) < 0)
  2166. X                exit(-1);
  2167. X            continue;
  2168. X        }
  2169. X
  2170. X        /* File is in packed format. Unpack it */
  2171. X
  2172. X        if((outfd = open(untemp, O_WRONLY | O_CREAT | O_EXCL)) < 0)
  2173. X        {
  2174. X            if(errno != EEXIST)
  2175. X            {
  2176. X                perror(untemp);
  2177. X                exit(-1);
  2178. X            }
  2179. X            if((outfd = open(untemp, O_WRONLY | O_TRUNC)) < 0)
  2180. X            {
  2181. X                perror(untemp);
  2182. X                exit(-1);
  2183. X            }
  2184. X        }
  2185. X
  2186. X        /* Start decompressing executable */
  2187. X
  2188. X        if(dodecode(infd, outfd) != 0)
  2189. X        {
  2190. X            if(unlink(untemp) < 0)
  2191. X                perror(untemp);
  2192. X            exit(-1);
  2193. X        }
  2194. X
  2195. X        (void)close(outfd);
  2196. X
  2197. X        /* Now set execute permissions on the beastie */
  2198. X
  2199. X        if(chmod(untemp, perms) < 0)
  2200. X        {
  2201. X            perror(untemp);
  2202. X            if(unlink(untemp) < 0)
  2203. X                perror(untemp);
  2204. X            exit(-1);
  2205. X        }
  2206. X
  2207. X        if(chown(untemp, owner, group) < 0)
  2208. X        {
  2209. X            perror(untemp);
  2210. X            if(unlink(untemp) < 0)
  2211. X                perror(untemp);
  2212. X            exit(-1);
  2213. X        }
  2214. X
  2215. X        /* Rename untemporary file to target executable and close target */
  2216. X
  2217. X        if(rename(untemp, expath) < 0)
  2218. X        {
  2219. X            perror(untemp);
  2220. X            if(unlink(untemp) < 0)
  2221. X                perror(untemp);
  2222. X            exit(-1);
  2223. X        }
  2224. X
  2225. X        (void)close(infd);
  2226. X
  2227. X        /* Everything OK!  Now go exec the executable. */
  2228. X
  2229. X        if(try_to_exec(expath, argv[0], argv) < 0)
  2230. X            exit(-1);
  2231. X    } /* for */
  2232. X} /* untcx_and_exec_local */
  2233. X#endif
  2234. X
  2235. X
  2236. void
  2237. untcx_and_exec_nfs(char *expath, char *untemp, char *targ, char *argv[])
  2238. X{
  2239. struct    stat    tostat;    /* Stat buffer to check on lengths */
  2240. int    mtime;
  2241. int    owner, group;
  2242. int    perms;        /* Saved permissions to restore on target exec */
  2243. int    infd, outfd;    /* In and out file descriptors */
  2244. struct    flock    lck;    /* File lock structure */
  2245. char    *c;
  2246. int    len;
  2247. X
  2248. X    /* Stat executable and grab permissions */
  2249. X
  2250. X#ifdef AIX
  2251. X    if(seteuid(getuid()) < 0) { perror("seteuid"); exit(-1); }
  2252. X#else
  2253. X    if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  2254. X#endif
  2255. X
  2256. X    if(stat(expath, &tostat) < 0) { perror(argv[0]); exit(-1); }
  2257. X
  2258. X    perms = (tostat.st_mode & 0777);
  2259. X    mtime = tostat.st_mtime;
  2260. X    owner = tostat.st_uid;
  2261. X    group = tostat.st_gid;
  2262. X
  2263. X    /* resolve first stage of argv[0] */
  2264. X
  2265. X    if(getwd(cwd) == NULL) { (void)fprintf(stderr, "Get Working Directory Error: %s\n", cwd); exit(-1); }
  2266. X
  2267. X    if(*argv[0] == '/') (void)strcpy(realdir, argv[0]); else (void)sprintf(realdir, "%s/%s", cwd, argv[0]);
  2268. X
  2269. X    if((c = strrchr(realdir, '/')) == NULL) { (void)fprintf(stderr, "Help! Internal corruption of variables!\n"); exit(-1); }
  2270. X
  2271. X    c++; (void)strcpy(execname, c); *c = '\0';
  2272. X
  2273. X    if(chdir(realdir) < 0) { perror(realdir); exit(-1); }
  2274. X
  2275. X    if(getwd(realdir) == NULL) { (void)fprintf(stderr, "Get Working Directory Error: %s\n", cwd); exit(-1); }
  2276. X
  2277. X    for(c = realdir; *c; c++)
  2278. X        if(*c == '/')
  2279. X            *c = '=';
  2280. X    (void)sprintf(linkpath, "%s/%s", ENFSDIR, realdir);
  2281. X    if(mkdir(linkpath, 0777) < 0)
  2282. X    {
  2283. X        if(errno != EEXIST) { perror(linkpath); exit(-1); }
  2284. X    }
  2285. X    else
  2286. X        (void)chmod(linkpath, 0777);
  2287. X    (void)strcat(linkpath,"/");
  2288. X    (void)strcat(linkpath, execname);
  2289. X
  2290. X    if(chdir(cwd) < 0) { perror(cwd); exit(-1); }
  2291. X    
  2292. X#ifdef AIX
  2293. X    if(seteuid(0) < 0) { perror("seteuid"); exit(-1); }
  2294. X#else
  2295. X    if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  2296. X#endif
  2297. X
  2298. X    /* Statistics done! Now try to unpack and run it! */
  2299. X
  2300. X    for(;;PUSLEEP(10000))
  2301. X    {
  2302. X        if(stat(targ, &tostat) >= 0)
  2303. X        {
  2304. X            if(mtime > tostat.st_mtime)
  2305. X            {
  2306. X                if(strcmp(linkpath, targ) == 0)
  2307. X                    (void)unlink(linkpath);
  2308. X                (void)unlink(targ);
  2309. X            }
  2310. X            else
  2311. X            {
  2312. X                if(strcmp(linkpath, targ) == 0)
  2313. X                {
  2314. X                    if(try_to_exec(targ, linkpath, argv) < 0) exit(-1); else continue;
  2315. X                }
  2316. X                else
  2317. X                if((len = readlink(linkpath, realdir, MAXPATHLEN)) >= 0 && strncmp(realdir, targ, len) == 0)
  2318. X                {
  2319. X                    if(try_to_exec(targ, linkpath, argv) < 0) exit(-1); else continue;
  2320. X                }
  2321. X                else
  2322. X                {
  2323. X                    (void)unlink(linkpath);
  2324. X
  2325. X                    if(symlink(targ, linkpath) < 0) { perror(linkpath); exit(-1); }
  2326. X
  2327. X                    if(try_to_exec(targ, linkpath, argv) < 0) exit(-1); else continue;
  2328. X                }
  2329. X            }
  2330. X        }
  2331. X        else
  2332. X        {
  2333. X            /* If symlink to file is there, then get rid of it! */
  2334. X
  2335. X            if((len = readlink(linkpath, realdir, MAXPATHLEN)) >= 0 && strncmp(realdir, targ, len) == 0)
  2336. X                (void)unlink(linkpath);
  2337. X        }
  2338. X
  2339. X#ifdef AIX
  2340. X        if(seteuid(getuid()) < 0) { perror("seteuid"); exit(-1); }
  2341. X#else
  2342. X        if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  2343. X#endif
  2344. X        if((infd = open(expath, O_RDONLY)) < 0)
  2345. X        {
  2346. X            perror(expath);
  2347. X            exit(-1);
  2348. X        }
  2349. X#ifdef AIX
  2350. X        if(seteuid(0) < 0) { perror("seteuid"); exit(-1); }
  2351. X#else
  2352. X        if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  2353. X#endif
  2354. X
  2355. X        if(! is_tcx(infd))
  2356. X        {
  2357. X            (void)close(infd);
  2358. X            if(try_to_exec(expath, argv[0], argv) < 0)
  2359. X                exit(-1);
  2360. X            continue;
  2361. X        }
  2362. X
  2363. X        /* File is in packed format. Unpack it */
  2364. X
  2365. X        if((outfd = open(untemp, O_EXCL | O_CREAT | O_WRONLY)) < 0)
  2366. X        {
  2367. X            if(errno != EEXIST)
  2368. X            {
  2369. X                perror(untemp);
  2370. X                exit(-1);
  2371. X            }
  2372. X            if((outfd = open(untemp, O_WRONLY | O_TRUNC)) < 0)
  2373. X            {
  2374. X                perror(untemp);
  2375. X                exit(-1);
  2376. X            }
  2377. X        }
  2378. X
  2379. X        lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  2380. X        if(fcntl(outfd, F_SETLK, &lck) < 0)
  2381. X        {
  2382. X            (void)close(infd);
  2383. X            (void)close(outfd);
  2384. X            continue;
  2385. X        }
  2386. X
  2387. X        /* Start decompressing executable */
  2388. X
  2389. X        if(dodecode(infd, outfd) != 0)
  2390. X        {
  2391. X            if(unlink(untemp) < 0)
  2392. X                perror(untemp);
  2393. X            exit(-1);
  2394. X        }
  2395. X
  2396. X        (void)close(infd);
  2397. X
  2398. X        /* Now set execute permissions on the beastie */
  2399. X
  2400. X        if(chmod(untemp, perms) < 0)
  2401. X        {
  2402. X            perror(untemp);
  2403. X            if(unlink(untemp) < 0)
  2404. X                perror(untemp);
  2405. X            exit(-1);
  2406. X        }
  2407. X
  2408. X        if(chown(untemp, owner, group) < 0)
  2409. X        {
  2410. X            perror(untemp);
  2411. X            if(unlink(untemp) < 0)
  2412. X                perror(untemp);
  2413. X            exit(-1);
  2414. X        }
  2415. X
  2416. X        /* Rename untemporary file to target executable and close target */
  2417. X
  2418. X        if(rename(untemp, targ) < 0)
  2419. X        {
  2420. X            perror(untemp);
  2421. X            if(unlink(untemp) < 0)
  2422. X                perror(untemp);
  2423. X            exit(-1);
  2424. X        }
  2425. X
  2426. X        (void)close(outfd);
  2427. X
  2428. X        /* Now create symlink from linkpath to targ if they are not equal */
  2429. X
  2430. X        if(strcmp(linkpath, targ) != 0 && symlink(targ, linkpath) < 0)
  2431. X        {
  2432. X            perror(linkpath);
  2433. X            exit(-1);
  2434. X        }
  2435. X
  2436. X        /* Everything OK!  Now go exec the executable. */
  2437. X
  2438. X        if(try_to_exec(targ, linkpath, argv) < 0)
  2439. X            exit(-1);
  2440. X    } /* for */
  2441. X} /* untcx_and_exec_nfs */
  2442. X
  2443. X
  2444. void
  2445. just_untcx(char *expath, char *untemp)
  2446. X{
  2447. struct    stat    tostat;    /* Stat buffer to check on lengths */
  2448. int    owner, group;
  2449. int    perms;        /* Saved permissions to restore on target exec */
  2450. int    infd, outfd;    /* In and out file descriptors */
  2451. struct    flock    lck;    /* File lock structure */
  2452. X
  2453. X    /* Stat executable and grab permissions */
  2454. X
  2455. X    if(stat(expath, &tostat) < 0)
  2456. X    {
  2457. X        perror(expath);
  2458. X        exit(-1);
  2459. X    }
  2460. X    perms = (tostat.st_mode & 0777);
  2461. X    owner = tostat.st_uid;
  2462. X    group = tostat.st_gid;
  2463. X
  2464. X    if((infd = open(expath, O_RDWR)) < 0)
  2465. X    {
  2466. X        perror(expath);
  2467. X        exit(-1);
  2468. X    }
  2469. X
  2470. X    lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  2471. X    if(fcntl(infd, F_SETLK, &lck) < 0)
  2472. X    {
  2473. X        perror(expath);
  2474. X        exit(-1);
  2475. X    }
  2476. X
  2477. X    if(! is_tcx(infd))
  2478. X    {
  2479. X        (void)fprintf(stderr, "File does not appear to be in tcx format. Aborting\n");
  2480. X        exit(-1);
  2481. X    }
  2482. X
  2483. X    /* File is in packed format. Unpack it */
  2484. X
  2485. X    if((outfd = open(untemp, O_WRONLY | O_CREAT | O_EXCL)) < 0)
  2486. X    {
  2487. X        if(errno != EEXIST)
  2488. X        {
  2489. X            perror(untemp);
  2490. X            exit(-1);
  2491. X        }
  2492. X        if((outfd = open(untemp, O_WRONLY | O_TRUNC)) < 0)
  2493. X        {
  2494. X            perror(untemp);
  2495. X            exit(-1);
  2496. X        }
  2497. X    }
  2498. X
  2499. X    /* Start decompressing executable */
  2500. X
  2501. X    if(dodecode(infd, outfd) != 0)
  2502. X    {
  2503. X        if(unlink(untemp) < 0)
  2504. X            perror(untemp);
  2505. X        exit(-1);
  2506. X    }
  2507. X
  2508. X    (void)close(outfd);
  2509. X
  2510. X    /* Now set execute permissions on the beastie */
  2511. X
  2512. X    if(chmod(untemp, perms) < 0)
  2513. X    {
  2514. X        perror(untemp);
  2515. X        if(unlink(untemp) < 0)
  2516. X            perror(untemp);
  2517. X        exit(-1);
  2518. X    }
  2519. X
  2520. X    if(chown(untemp, owner, group) < 0)
  2521. X    {
  2522. X        perror(untemp);
  2523. X        if(unlink(untemp) < 0)
  2524. X            perror(untemp);
  2525. X        exit(-1);
  2526. X    }
  2527. X
  2528. X    /* Rename untemporary file to target executable and close target */
  2529. X
  2530. X    if(rename(untemp, expath) < 0)
  2531. X    {
  2532. X        perror(untemp);
  2533. X        if(unlink(untemp) < 0)
  2534. X            perror(untemp);
  2535. X        exit(-1);
  2536. X    }
  2537. X
  2538. X    (void)close(infd);
  2539. X    return;
  2540. X} /* just_untcx */
  2541. X
  2542. X
  2543. int
  2544. try_to_exec(char *expath, char *lnpath, char *argv[])
  2545. X{
  2546. int    infd, try;
  2547. int    logfd;
  2548. XFILE    *logfp;
  2549. struct    flock    lck;
  2550. X
  2551. X    if((infd = open(lnpath, O_RDONLY)) < 0)
  2552. X    {
  2553. X        if(errno == ENOENT)
  2554. X        {
  2555. X            perror(lnpath);
  2556. X            return -1;
  2557. X        }
  2558. X        return 0;
  2559. X    }
  2560. X
  2561. X    if(is_tcx(infd))
  2562. X    {
  2563. X        (void)close(infd);
  2564. X        return 0;
  2565. X    }
  2566. X
  2567. X    lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  2568. X    for(try = 0; try < 10; try++, PUSLEEP(50000))
  2569. X    {
  2570. X        if((logfd = open(logpath, O_WRONLY)) < 0)
  2571. X            continue;
  2572. X        if(fcntl(logfd, F_SETLK, &lck) < 0)
  2573. X        {
  2574. X            (void)close(logfd);
  2575. X            continue;
  2576. X        }
  2577. X
  2578. X        if((logfp = fopen(logpath, "a+")) == NULL)
  2579. X        {
  2580. X            (void)close(logfd);
  2581. X            continue;
  2582. X        }
  2583. X
  2584. X#ifdef UNPACK_IN_PLACE
  2585. X        (void)fprintf(logfp, "%s\n", expath);
  2586. X#else
  2587. X        if(strstr(expath, ENFSDIR) == expath)
  2588. X            (void)fprintf(logfp, "%s\n", expath);
  2589. X#endif
  2590. X        if((strstr(lnpath, ENFSDIR) == lnpath) && (strcmp(lnpath, expath) != 0))
  2591. X            (void)fprintf(logfp, "%s\n", lnpath);
  2592. X        (void)fclose(logfp);
  2593. X        (void)close(logfd);
  2594. X        break;
  2595. X    }
  2596. X
  2597. X#if defined(IRIX) || defined(AIX)
  2598. X    if(setuid(getuid()) < 0) { perror("setuid"); exit(-1); }
  2599. X#else
  2600. X    if(setreuid(getuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  2601. X#endif
  2602. X
  2603. X    /* Reset signals back to normal to prevent carriage through execv */
  2604. X
  2605. X    (void)signal(SIGINT, SIG_DFL);
  2606. X    (void)signal(SIGHUP, SIG_DFL);
  2607. X    (void)signal(SIGTSTP, SIG_DFL);
  2608. X    (void)signal(SIGALRM, SIG_DFL);
  2609. X    (void)signal(SIGQUIT, SIG_DFL);
  2610. X    (void)signal(SIGTERM, SIG_DFL);
  2611. X
  2612. X    (void)close(infd);
  2613. X    if(execv(lnpath, argv) < 0)
  2614. X        perror(lnpath);
  2615. X    return -1;
  2616. X} /* try_to_exec */
  2617. X
  2618. X
  2619. X#if defined(SUNOS)
  2620. void
  2621. update_pstat_info()
  2622. X{
  2623. XFILE    *fp;
  2624. char    line[256], tmp[10];
  2625. pstat    *curr;
  2626. int    i, pos;
  2627. int    maj, min, dev, ino, cnt;
  2628. X
  2629. X    for(pos = 0 ; pos < MAXOPENFILES; pos++)
  2630. X        pihash[pos] = (pstat *)NULL;
  2631. X
  2632. X    if((fp = popen(PSTATI, "r")) == NULL)
  2633. X        return;
  2634. X    if(fgets(line, 256, fp) == NULL)
  2635. X        return;
  2636. X    for(i = 0; fgets(line, 256, fp) != NULL && i < MAXOPENFILES; i++)
  2637. X    {
  2638. X        curr = parr + i;
  2639. X        strncpy(tmp, line+16, 3);    tmp[3] = '\0';    maj = atoi(tmp);
  2640. X        strncpy(tmp, line+20, 3);    tmp[3] = '\0';    min = atoi(tmp);
  2641. X        strncpy(tmp, line+23, 6);    tmp[6] = '\0';    ino = atoi(tmp);
  2642. X        strncpy(tmp, line+61, 4);    tmp[4] = '\0';    cnt = atoi(tmp);
  2643. X        dev = maj * 256 + min;
  2644. X        pos = PIHASH(dev, ino);
  2645. X        curr->dev = dev;
  2646. X        curr->ino = ino;
  2647. X        curr->cnt = cnt;
  2648. X        curr->next = pihash[pos];
  2649. X        pihash[pos] = curr;
  2650. X    } /* while */
  2651. X    pclose(fp);
  2652. X} /* update_pstat_info */
  2653. X#endif
  2654. X
  2655. X
  2656. int
  2657. scan_logtail(int lastoff)
  2658. X{
  2659. char    newpath[MAXPATHLEN], *s;
  2660. int    len;
  2661. XFILE    *logfp;
  2662. path    *curr;
  2663. struct    stat    sb;
  2664. X
  2665. X    if(lastoff < 0)
  2666. X        lastoff = 0;
  2667. X    if((logfp = fopen(logpath, "r")) == NULL)
  2668. X        return -1;
  2669. X    (void)fseek(logfp, lastoff, SEEK_SET);
  2670. X    while(fgets(newpath, MAXPATHLEN, logfp) != NULL)
  2671. X    {
  2672. X        for(s = newpath; *s; s++) if(*s == '\n') *s = '\0';
  2673. X
  2674. X        if(lstat(newpath, &sb) < 0)
  2675. X            continue;
  2676. X
  2677. X        for(curr = worklist; curr != NULL; curr = curr->next)
  2678. X            if(strcmp(curr->path, newpath) == 0) break;
  2679. X
  2680. X        if(curr != NULL)    /* Reset indicators on known file */
  2681. X        {
  2682. X            curr->ctime = sb.st_ctime;
  2683. X#ifdef UNPACK_IN_PLACE
  2684. X            curr->pid = -1;
  2685. X            (strstr(newpath, ENFSDIR) == newpath) ? (curr->local = 0) : (curr->local = 1);
  2686. X#endif
  2687. X            continue;
  2688. X        }
  2689. X
  2690. X        if(freelist != NULL)
  2691. X        {
  2692. X            curr = freelist;
  2693. X            freelist = freelist->next;
  2694. X        }
  2695. X        else
  2696. X            if((curr = (path *)malloc(sizeof(path))) == NULL)
  2697. X                continue;
  2698. X
  2699. X        (void)strcpy(curr->path, newpath);
  2700. X#ifdef UNPACK_IN_PLACE
  2701. X        curr->pid = -1;
  2702. X        (strstr(newpath, ENFSDIR) == newpath) ? (curr->local = 0) : (curr->local = 1);
  2703. X#endif
  2704. X        curr->atime = sb.st_atime;
  2705. X        curr->ctime = sb.st_ctime;
  2706. X        curr->next = worklist;
  2707. X        worklist = curr;
  2708. X    } /* while */
  2709. X    lastoff = ftell(logfp);
  2710. X    (void)fclose(logfp);
  2711. X    return lastoff;
  2712. X} /* scan_logtail */
  2713. X
  2714. X
  2715. X#ifdef UNPACK_IN_PLACE
  2716. int
  2717. is_dir_local(char *dir)
  2718. X{
  2719. X#if defined(ULTRIX)
  2720. struct  fs_data fsbuf;
  2721. int    success = 1;     /* Returns 0 on "NOT MOUNTED" */
  2722. X#else
  2723. struct    statfs    fsbuf;    /* Statfs buffer to check local versus NFS executable */
  2724. int    success = 0;    
  2725. X#endif
  2726. X
  2727. X#if defined(IRIX)
  2728. X    if(statfs(dir, &fsbuf, (int)(sizeof(struct statfs)), 0) < success)
  2729. X#else
  2730. X    if(statfs(dir, &fsbuf) < success)
  2731. X#endif
  2732. X        return -1;
  2733. X
  2734. X    /* NFS Version 2 returns -1 or 0 for both free inodes, and total */
  2735. X    /* inodes to a client, so return false on this condition. */
  2736. X
  2737. X#if defined(ULTRIX)
  2738. X    if((fsbuf.fd_req.gfree <= 0) && (fsbuf.fd_req.gtot <= 0))
  2739. X#else
  2740. X    if((fsbuf.f_files <= 0) && (fsbuf.f_ffree <= 0))
  2741. X#endif
  2742. X        return 0;
  2743. X    return 1;
  2744. X} /* is_dir_local */
  2745. X#endif
  2746. X
  2747. X
  2748. int
  2749. is_tcx(int fd)
  2750. X{
  2751. int    i;
  2752. unsigned char    c;
  2753. X
  2754. X    for(i = 0; i < 256; i++)
  2755. X        if(read(fd, &c, 1) < 1 || c == 0)
  2756. X            break;
  2757. X    if((i >= 256) || read(fd, &c, 1) < 1  || c != 76 || read(fd, &c, 1) < 1  || c != 193
  2758. X        || read(fd, &c, 1) < 1  || c != 13 || read(fd, &c, 1) < 1  || c != 138 )
  2759. X        return 0;
  2760. X    return 1;
  2761. X} /* is_tcx */
  2762. X
  2763. X
  2764. int
  2765. dodecode(int infd, int outfd)
  2766. X{
  2767. int    pid;
  2768. X#if defined(IRIX) || defined(AIX)
  2769. int    status;
  2770. X#else
  2771. union wait status;
  2772. X#endif
  2773. X
  2774. X    pid = fork();
  2775. X    if(pid < 0) return -1;
  2776. X    if(pid == 0)
  2777. X    {
  2778. X        if(dup2(infd, 0) < 0) exit(-1);     /* Attach infd to stdin */
  2779. X        (void)close(infd);
  2780. X        if(dup2(outfd, 1) < 0) exit(-1); /* Attach outfd to stdout */
  2781. X        (void)close(outfd);
  2782. X#ifdef    UNPACKOPTS
  2783. X        (void)execl(PATHUNPACK, PATHUNPACK, UNPACKOPTS, (char *)0);
  2784. X#else
  2785. X        (void)execl(PATHUNPACK, PATHUNPACK, (char *)0);
  2786. X#endif
  2787. X        exit(-1);
  2788. X    }
  2789. X    else
  2790. X        pid = wait(&status);
  2791. X    return WEXITSTATUS(status);
  2792. X} /* dodecode */
  2793. X
  2794. X
  2795. X#ifdef ULTRIX
  2796. int
  2797. usleep(int usec)
  2798. X{
  2799. struct    itimerval    value, dumb;
  2800. X
  2801. X    (void)signal(SIGALRM, usleep_sig);
  2802. X
  2803. X    if(getitimer(ITIMER_REAL, &value) != 0)
  2804. X    {
  2805. X        perror("Error: couldn't get timer");
  2806. X        return(-1);
  2807. X    }
  2808. X    value.it_value.tv_sec = value.it_interval.tv_sec = (long) usec / 1000000;
  2809. X    value.it_value.tv_usec = value.it_interval.tv_usec = (long) usec % 1000000;
  2810. X        
  2811. X    if(setitimer(ITIMER_REAL, &value, &dumb) != 0) /* ignore parameter 3 */
  2812. X    {
  2813. X        perror("Error: couldn't set timer");
  2814. X        return(-1);
  2815. X    }
  2816. X
  2817. X    (void)sigpause(SIGALRM);
  2818. X
  2819. X    if(getitimer(ITIMER_REAL, &value) != 0)
  2820. X    {
  2821. X        perror("Error: couldn't get timer");
  2822. X        return(-1);
  2823. X    }
  2824. X    usec = (value.it_value.tv_sec - value.it_interval.tv_sec) * 1000000;
  2825. X    usec += (value.it_value.tv_usec - value.it_interval.tv_usec);
  2826. X    return usec;
  2827. X}
  2828. X
  2829. int
  2830. usleep_sig()
  2831. X{
  2832. X} /* usleep_sig */
  2833. X#endif
  2834. END_OF_FILE
  2835. if test 31646 -ne `wc -c <'untcx.c'`; then
  2836.     echo shar: \"'untcx.c'\" unpacked with wrong size!
  2837. fi
  2838. # end of 'untcx.c'
  2839. fi
  2840. echo shar: End of archive 1 \(of 1\).
  2841. cp /dev/null ark1isdone
  2842. MISSING=""
  2843. for I in 1 ; do
  2844.     if test ! -f ark${I}isdone ; then
  2845.     MISSING="${MISSING} ${I}"
  2846.     fi
  2847. done
  2848. if test "${MISSING}" = "" ; then
  2849.     echo You have the archive.
  2850.     rm -f ark[1-9]isdone
  2851. else
  2852.     echo You still need to unpack the following archives:
  2853.     echo "        " ${MISSING}
  2854. fi
  2855. ##  End of shell archive.
  2856. exit 0
  2857.